diff -u --recursive --new-file v2.3.99-pre5/linux/CREDITS linux/CREDITS
--- v2.3.99-pre5/linux/CREDITS	Tue Apr 11 15:09:10 2000
+++ linux/CREDITS	Mon Apr 24 13:39:33 2000
@@ -268,10 +268,10 @@
 D: Original author of the Linux networking code
 
 N: Anton Blanchard
-E: anton@progsoc.uts.edu.au
-W: http://www.progsoc.uts.edu.au/~anton/
+E: anton@linuxcare.com
+W: http://linuxcare.com.au/anton/
 P: 1024/8462A731 4C 55 86 34 44 59 A7 99  2B 97 88 4A 88 9A 0D 97
-D: sun4 port
+D: sun4 port, Sparc hacker
 S: 47 Robert Street
 S: Marrickville NSW 2204
 S: Australia
@@ -941,17 +941,13 @@
 D: Selection mechanism
 
 N: Andre Hedrick
+E: andre@linux-ide.org
 E: andre@suse.com
 D: Random SMP kernel hacker...
 D: Uniform Multi-Platform E-IDE driver
-D: AEC6210UF Ultra33
-D: Aladdin 1533/1543(C) chipset
-D: Active-Chipset maddness..........
-D: HighPoint HPT343/5 Ultra/33 & HPT366 Ultra/66 chipsets
-D: Intel PIIX chipset
-D: Promise PDC20246/20247 & PDC20262 chipsets
-D: SiS5513 Ultra/66/33 chipsets
-D: VIA 82C586/596/686 chipsets
+D: Active-ATA-Chipset maddness..........
+D: Ultra DMA 66/33
+D: ATA-Smart Kernel Daemon
 S: 580 Second Street, Suite 2
 S: Oakland, CA
 S: USA
@@ -1148,6 +1144,7 @@
 D: 4.4BSD and NeXTstep filesystem support in the old ufs.
 D: Openstep filesystem and NeXTstep CDROM support in the new ufs.
 D: Replace CPU==[3-6]86 and __i386__ submodel flags by configuration options.
+D: Replace __SMP__ by CONFIG_SMP.
 D: Danish HOWTO, Linux+FreeBSD mini-HOWTO.
 S: Dr. Holsts Vej 34, lejl. 164
 S: DK-8230 Åbyhøj
@@ -1173,6 +1170,7 @@
 W: http://linux.powertweak.com
 D: Moved PCI bridge tuning to userspace (Powertweak).
 D: Centaur/IDT Winchip/Winchip 2 tweaks.
+D: AFFS fixes for 2.3.x
 D: Misc clean ups and other random hacking.
 S: 28, Laura Street,
 S: Treforest, Pontypridd,
@@ -1791,6 +1789,13 @@
 S: Derbyshire DE4 3RL
 S: United Kingdom
 
+N: Ian S. Nelson
+E: ian.nelson@echostar.com
+D: Minor mmap and ide hacks
+S: 1370 Atlantis Ave.
+S: Lafayette CO, 80026
+S: USA
+
 N: Russell Nelson
 E: nelson@crynwr.com
 W: http://www.crynwr.com/~nelson
@@ -2262,6 +2267,10 @@
 S: Richardson, Texas
 S: USA
 
+N: Christopher Smith
+E: x@xman.org
+D: Tulip net driver hacker
+
 N: Miquel van Smoorenburg
 E: miquels@cistron.nl
 D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
@@ -2293,6 +2302,13 @@
 S: Warburgring 67
 S: 66424 Homburg 
 S: Germany
+
+N: Andrew Stanley-Jones
+E: asj@lanmedia.com
+D: LanMedia Corp. Device WAN card device driver
+S: #102, 686 W. Maude Ave
+S: Sunyvale, CA 94086
+S: USA
 
 N: Henrik Storner
 E: storner@image.dk
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/Changes linux/Documentation/Changes
--- v2.3.99-pre5/linux/Documentation/Changes	Mon Mar 27 08:08:20 2000
+++ linux/Documentation/Changes	Thu Apr 13 22:45:43 2000
@@ -62,7 +62,7 @@
 - Bash                   1.14.7                  ; bash -version
 - Ncpfs                  2.2.0                   ; ncpmount -v
 - Pcmcia-cs              3.1.2                   ; cardmgr -V
-- PPP                    2.3.11                  ; pppd --version
+- PPP                    2.4.0b1                 ; pppd --version
 - Util-linux             2.9i                    ; chsh -v
 - isdn4k-utils           v3.1beta7               ; isdnctrl 2>&1|grep version
 
@@ -391,22 +391,33 @@
 PPP
 ===
 
-   Due to changes in the PPP driver and routing code, those of you
+   The PPP driver has been restructured to support multilink and
+to enable it to operate over diverse kinds of media.  Those of you
 using PPP networking will need to upgrade your pppd to at least
-version 2.3.11. See ftp://cs.anu.edu.au/pub/software/ppp/ for newest
-versions.
+version 2.4.0b1.  See ftp://linuxcare.com.au/pub/ppp/ for the latest
+version.
 
-   You must make sure that the special device file /dev/ppp exists.
-It can be made by executing this command as root:
+   If you are not using devfs, you must make sure that the special
+device file /dev/ppp exists.  It can be made by executing this command
+as root:
 
 	mknod /dev/ppp c 108 0
 
    If you have built ppp support as modules, you should put the lines
-below in your /etc/modules.conf file. I assume you want asynchronous
-ppp; replace ppp_async by ppp_synctty if you want synchronous ppp.
+below in your /etc/modules.conf file.
 
-	alias char-major-108 ppp_generic
-	alias tty-ldisc-3 ppp_async
+	alias char-major-108	ppp_generic
+	alias /dev/ppp		ppp_generic
+	alias tty-ldisc-3	ppp_async
+	alias tty-ldisc-14	ppp_synctty
+	alias ppp-compress-21	bsd_comp
+	alias ppp-compress-24	ppp_deflate
+	alias ppp-compress-26	ppp_deflate
+
+If you are using devfsd and you have ppp_generic as a module, put the
+following line in your /etc/devfsd.conf:
+
+	LOOKUP		ppp		MODLOAD
 
 iBCS
 ====
@@ -425,12 +436,6 @@
    fuser, which comes with psmisc, reads /proc/*/fd/* to do its job.
 Upgrade psmisc if 2.2 changes to /proc broke the version you're using.
 
-Tunelp
-======
-
-   A new version of tunelp is available which will allow you to enable
-"trustirq" mode, improving printing while using IRQ-driven lp ports.
-
 PCI utils
 =========
 
@@ -525,6 +530,17 @@
 you need to install the LVM tools. More information can be found at the home page
 of the LVM project at http://linux.msede.com/lvm/.
 
+Inline Documentation
+====================
+Many of the functions available for modules to use are now documented
+with specially-formatted comments near their definitions.  These
+comments can be combined with the SGML templates in the
+Documentation/DocBook directory to make DocBook files, which can then
+be combined with DocBook stylesheets to make PostScript documents,
+HTML pages, PDF files, and so on.  In order to convert from DocBook
+format to a format of your choice, you'll need to install jade, as
+well as some stylesheets.
+
 
 Where to get the files
 **********************
@@ -718,8 +734,8 @@
 PPP
 ===
 
-The 2.3.11 release:
-ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.11.tar.gz
+The 2.4.0b1 release:
+ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz
 
 IP Chains
 =========
@@ -775,12 +791,6 @@
 http://linux.powertweak.com/files/powertweak-0.1.2.tgz
 ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/powertweak/powertweak-0.1.2.tgz
 
-Tunelp
-======
-
-The 0-2.1.131 release:
-ftp://e-mind.com/pub/linux/tunelp/tunelp-0-2.1.131.tar.gz
-
 Xosview
 =======
 
@@ -817,6 +827,17 @@
 
 The 0.7 release:
 ftp://linux.msede.com/lvm/v0.7/lvm_0.7.tar.gz
+
+Jade
+====
+
+The 1.2.1 release:
+ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz
+
+DSSSL Stylesheets for the DocBook DTD
+=====================================
+
+http://nwalsh.com/docbook/dsssl/
 
 
 Other Info
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.99-pre5/linux/Documentation/Configure.help	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/Configure.help	Mon Apr 24 16:15:01 2000
@@ -18,7 +18,7 @@
 #   - Polish, by Cezar Cichocki (cezar@cs.net.pl), at
 #     http://www.cs.net.pl/~cezar/Kernel
 #   - German, by SuSE, at http://www.suse.de/~ke/kernel . This patch
-#     includes infrastructure to support different languages as well.
+#     also includes infrastructure to support different languages.
 #
 # 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
@@ -187,48 +187,44 @@
 
 High Memory support
 CONFIG_NOHIGHMEM
-  If you are compiling a kernel which will never run on a machine
-  with more than 1 Gigabyte total physical RAM, answer "off"
-  here (default choice).  This will result in the old "3GB/1GB"
-  virtual/physical memory split. 3GB are mapped so as each processus
-  sees a 3GB virtual memory space.
-  The remaining part of the 4GB virtual memory space is used by the
-  kernel to 'permanently map' as much physical memory as possible.
-  Certain types of applications perform better if there is more
-  'permanently mapped' kernel memory.
-  Certain types of applications (eg. database servers) perform
-  better if they have as much virtual memory per process as possible.
-
   Linux can use up to 64 Gigabytes of physical memory on x86 systems.
-  However 32-bit x86 processors have only 4 Gigabytes of virtual memory
-  space. 
-
-  Any potentially remaining part of physical memory is called
-  'high memory' that is all the physical RAM that could not be directly
-  mapped by the kernel - ie. 3GB if there is 4GB RAM in the system,
-  7GB if there is 8GB RAM in the system.
+  However, the address space of 32-bit x86 processors is only 4
+  Gigabytes large. That means that, if you have a large amount of
+  physical memory, not all of it can be "permanently mapped" by the
+  kernel. The physical memory that's not permanently mapped is called
+  "high memory".
+
+  If you are compiling a kernel which will never run on a machine with
+  more than 1 Gigabyte total physical RAM, answer "off" here (default
+  choice and suitable for most users). This will result in a "3GB/1GB"
+  split: 3GB are mapped so that each process sees a 3GB virtual memory
+  space and the remaining part of the 4GB virtual memory space is used
+  by the kernel to permanently map as much physical memory as
+  possible.
 
-  If 4 Gigabytes physical RAM or less is used then answer "4GB" here.
+  If the machine has between 1 and 4 Gigabytes physical RAM, then
+  answer "4GB" here.
 
   If more than 4 Gigabytes is used then answer "64GB" here. This
   selection turns Intel PAE (Physical Address Extension) mode on.
   PAE implements 3-level paging on IA32 processors. PAE is fully
   supported by Linux, PAE mode is implemented on all recent Intel
-  processors (PPro and better). NOTE: The "64GB" kernel will not
-  boot CPUs that not support PAE!
+  processors (Pentium Pro and better). NOTE: If you say "64GB" here,
+  then the kernel will not boot on CPUs that don't support PAE!
 
   The actual amount of total physical memory will either be
-  autodetected or can be forced by using a kernel command line option
+  auto detected or can be forced by using a kernel command line option
   such as "mem=256M". (Try "man bootparam" or see the documentation of
   your boot loader (lilo or loadlin) about how to pass options to the
-  kernel at boot time. The lilo procedure is also explained in the
-  SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto .)
+  kernel at boot time.) 
+
+  If unsure, say "off".
 
 Normal PC floppy disk support
 CONFIG_BLK_DEV_FD
   If you want to use the floppy disk drive(s) of your PC under Linux,
   say Y. Information about this driver, especially important for IBM
-  Thinkpad users, is contained in drivers/block/README.fd. This file
+  Thinkpad users, is contained in Documentation/floppy.txt. That file
   also contains the location of the Floppy driver FAQ as well as
   location of the fdutils package used to configure additional
   parameters of the driver at run time.
@@ -276,7 +272,9 @@
   Saying Y here will allow you to use a regular file as a block
   device; you can then create a file system on that block device and
   mount it just as you would mount other block devices such as hard
-  drive partitions, CDROM drives or floppy drives.
+  drive partitions, CDROM drives or floppy drives. The loop devices
+  are block special device files with major number 7 and typically
+  called /dev/loop0, /dev/loop1 etc.
 
   This is useful if you want to check an ISO 9660 file system before
   burning the CD, or if you want to use floppy images without first
@@ -291,17 +289,18 @@
   bits of, say, a sound file). This is also safe if the file resides
   on a remote file server. If you want to do this, you will first have
   to acquire and install a kernel patch from
-  ftp://ftp.replay.com/pub/crypto/linux/all or
-  ftp://verden.pvv.org/pub/linux/kerneli/v2.1/ , and then you need to
+  ftp://ftp.kerneli.org/pub/kerneli/ , and then you need to
   say Y to this option.
 
   Note that alternative ways to use encrypted file systems are
   provided by the cfs package, which can be gotten from
-  ftp://ftp.replay.com/pub/crypto/disk/ , and the newer tcfs package,
-  available at http://tcfs.dia.unisa.it/ . You do not need to say Y
-  here if you want to use one of these. However, using cfs requires
-  saying Y to "NFS file system support" below while using tcfs
-  requires applying a kernel patch.
+  ftp://ftp.kerneli.org/pub/kerneli/net-source/ , and the newer tcfs
+  package, available at http://tcfs.dia.unisa.it/ . You do not need to
+  say Y here if you want to use one of these. However, using cfs
+  requires saying Y to "NFS file system support" below while using
+  tcfs requires applying a kernel patch. An alternative steganography
+  solution is provided by StegFS, also available from
+  ftp://ftp.kerneli.org/pub/kerneli/net-source/ .
 
   To use the loop device, you need the losetup utility and a recent
   version of the mount program, both contained in the util-linux
@@ -533,8 +532,11 @@
   drives, similar to the SCSI protocol. 
 
   The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by
-  this driver. (ATAPI PD-CD/CDR drives are not supported by this
-  driver; support for PD-CD/CDR drives is available if you answer Y to
+  this driver. For information about jumper settings and the question
+  of when a ZIP drive uses a partition table, see
+  http://www.win.tue.nl/~aeb/linux/zip/zip-1.html .
+  (ATAPI PD-CD/CDR drives are not supported by this driver; support
+  for PD-CD/CDR drives is available if you answer Y to 
   "SCSI emulation support", below).
 
   If you say Y here, the FLOPPY drive will be identified along with
@@ -715,21 +717,25 @@
 
   Please read the comments at the top of drivers/scsi/3w-xxxx.c  
 
-AEC6210 chipset support
-CONFIG_BLK_DEV_AEC6210
+AEC62XX chipset support
+CONFIG_BLK_DEV_AEC62XX
   This driver adds up to 4 more EIDE devices sharing a single
   interrupt. This add-on card is a bootable PCI UDMA controller. In
   order to get this card to initialize correctly in some cases, you
   should say Y here, and preferably also to "Use DMA by default when
   available".
 
-  Please read the comments at the top of drivers/ide/aec6210.c If
-  you say Y here, then say Y to "Use DMA by default when available" as
+  The ATP850U/UF is an UltraDMA 33 chipset base.
+  The ATP860 is an UltraDMA 66 chipset base.
+  The ATP860M(acintosh) version is an UltraDMA 66 chipset base.
+
+  Please read the comments at the top of drivers/ide/aec62xx.c
+  If you say Y here, then say Y to "Use DMA by default when available" as
   well.
 
-AEC6210 Tuning support (WIP)
-CONFIG_AEC6210_TUNING
-  Please read the comments at the top of drivers/ide/aec6210.c  
+AEC62XX Tuning support (WIP)
+CONFIG_AEC62XX_TUNING
+  Please read the comments at the top of drivers/ide/aec62xx.c  
   If unsure, say N.
 
 ALI M15x3 chipset support
@@ -969,6 +975,12 @@
 
   If unsure, say N.
 
+VIA82CXXX Tuning support (WIP)
+CONFIG_VIA82CXXX_TUNING
+  Please read the comments at the top of drivers/ide/via82cxxx.c
+
+  If unsure, say N.
+
 Other IDE chipset support
 CONFIG_IDE_CHIPSETS
   Say Y here if you want to include enhanced support for various IDE
@@ -1417,7 +1429,7 @@
   devices named /dev/VolumeGroupName/LogicalVolumeName.
 
   For details see Documentation/LVM-HOWTO. You will need supporting
-  user space software from http://linux.msede.com/lvm .
+  user space software; location is in Documentation/Changes.
 
   If you want to compile this support as a module ( = code which can
   be inserted in and removed from the running kernel whenever you
@@ -1437,12 +1449,12 @@
 CONFIG_BLK_DEV_MD
   This driver lets you combine several hard disk partitions into one
   logical block device. This can be used to simply append one
-  partition to another one or to combine several redundant
-  hard disks to a RAID1/4/5 device so as to provide protection against
-  hard disk failures. This is called "Software RAID" since the
-  combining of the partitions is done by the kernel. "Hardware RAID"
-  means that the combining is done by a dedicated controller; if you
-  have such a controller, you do not need to say Y here.
+  partition to another one or to combine several redundant hard disks
+  into a RAID1/4/5 device so as to provide protection against hard
+  disk failures. This is called "Software RAID" since the combining of
+  the partitions is done by the kernel. "Hardware RAID" means that the
+  combining is done by a dedicated controller; if you have such a
+  controller, you do not need to say Y here.
 
   More information about Software RAID on Linux is contained in the
   Software-RAID mini-HOWTO, available from
@@ -1510,7 +1522,7 @@
 RAID-4/RAID-5 mode
 CONFIG_MD_RAID5
   A RAID-5 set of N drives with a capacity of C MB per drive provides
-  the capacity of C * (N - 1) drives, and protects against a failure
+  the capacity of C * (N - 1) MB, and protects against a failure
   of a single drive. For a given sector (row) number, (N - 1) drives
   contain data sectors, and one drive contains the parity protection.
   For a RAID-4 set, the parity blocks are present on a single drive,
@@ -1619,6 +1631,56 @@
   4000, Acer PICA, Olivetti M700-10 and a few other identical OEM
   systems.
 
+PCMCIA SCSI adapter support
+CONFIG_SCSI_PCMCIA
+  Say Y here if you intend to attach a PCMCIA or CardBus card to your
+  computer which acts as a SCSI host adapter. These are credit card
+  size devices often used with laptops.
+
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause this configure script to skip all
+  the questions PCMCIA SCSI host adapters.
+
+Adaptec AHA152X PCMCIA support
+CONFIG_PCMCIA_AHA152X
+  Say Y here if you intend to attach this type of PCMCIA SCSI host
+  adapter to your computer.
+
+  This driver is also available as a module called aha152x_cs.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+Qlogic PCMCIA support
+CONFIG_PCMCIA_QLOGIC
+  Say Y here if you intend to attach this type of PCMCIA SCSI host
+  adapter to your computer.
+
+  This driver is also available as a module called qlogic_cs.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+Future Domain PCMCIA support
+CONFIG_PCMCIA_FDOMAIN
+  Say Y here if you intend to attach this type of PCMCIA SCSI host
+  adapter to your computer.
+
+  This driver is also available as a module called fdomain_cs.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+Adaptec APA1480 CardBus support
+CONFIG_PCMCIA_APA1480
+  Say Y here if you intend to attach this type of CardBus SCSI host
+  adapter to your computer.
+
+  This driver is also available as a module called apa1480_cb.o ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
 CPU type
 CONFIG_CPU_R3000
   Please make sure to pick the right CPU type. Linux/MIPS is not
@@ -1709,8 +1771,8 @@
 
   Various modules exist for netfilter which replace the previous
   masquerading (ipmasqadm), packet filtering (ipchains), transparent
-  proxying, and portforwarding mechanisms. More information is
-  available from http://netfilter.kernelnotes.org .
+  proxying, and portforwarding mechanisms. Please see
+  Documentation/Changes for the location of these packages.
  
   Make sure to say N to "Fast switching" below if you intend to say Y
   here, as Fast switching currently bypasses netfilter.
@@ -1746,10 +1808,10 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `Y'.
 
-IP: userspace queueing via NETLINK (EXPERIMENTAL)
+IP: user space queueing via NETLINK (EXPERIMENTAL)
 CONFIG_IP_NF_QUEUE
-  Netfilter has the ability to queue packets to userspace: the netlink
-  device can be used to access them using this driver.
+  Netfilter has the ability to queue packets to user space: the
+  netlink device can be used to access them using this driver.
 
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
@@ -3808,12 +3870,17 @@
   
 Kernel httpd acceleration (EXPERIMENTAL)
 CONFIG_KHTTPD
-  The kernel httpd acceleration daemon (kHTTPd) is a (limited) 
-  web server built into the kernel. It is limited since it can only
-  serve files from the file system. Saying "M" here builds the
-  kHTTPd module; this is NOT enough to have a working kHTTPd. 
-  For safety reasons, the module has to be activated by doing a
-  "echo 1 > /proc/sys/net/khttpd/start" after inserting the module.
+  The kernel httpd acceleration daemon (kHTTPd) is a (limited) web
+  server built into the kernel. It is limited since it can only serve
+  files from the file system and cannot deal with executable content
+  such as CGI scripts. Serving files is sped up if you use kHTTPd.
+  If kHTTPd is not able to fulfill a request, it can transparently
+  pass it through to a user space web server such as apache.
+
+  Saying "M" here builds the kHTTPd module; this is NOT enough to have
+  a working kHTTPd. For safety reasons, the module has to be activated
+  by doing a "echo 1 > /proc/sys/net/khttpd/start" after inserting the
+  module.
 
   Before using this, read the README in net/khttpd !
 
@@ -4841,12 +4908,16 @@
   say N here.
 
 FORE Systems 200E-series
-CONFIG_ATM_FORE200E
+CONFIG_ATM_FORE200E_MAYBE
   This is a driver for the FORE Systems 200E-series ATM adapter
   cards. It simultaneously supports PCA-200E and SBA-200E models
   on PCI and SBUS hosts. Say Y (or M to compile as a module
   named fore_200e.o) here if you have one of these ATM adapters.
  
+  Note that the driver will actually be compiled only if you
+  additionally enable the support for PCA-200E and/or SBA-200E
+  cards.
+
   See the file Documentation/networking/fore200e.txt for further
   details.
  
@@ -5026,15 +5097,17 @@
   about anything having "SCSI" in its name other than hard disks,
   CDROMs or tapes, say Y here. These won't be supported by the kernel
   directly, so you need some additional software which knows how to
-  talk to these devices using the SCSI protocol. For scanners, look at
-  SANE (www.mostang.com/sane). For CD writer software look at cdrecord
-  (www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private
-  /cdrecord.html) and for burning a "disk at once": cdrdao
-  (www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high quality
-  digital reader of audio CDs (www.xiph.org/paranoia).
-  For other devices, it's possible that you'll have to write the driver
-  software yourself. Please read the file Documentation/scsi-generic.txt
-  for more information.
+  talk to these devices using the SCSI protocol:
+
+  For scanners, look at SANE (http://www.mostang.com/sane). For CD
+  writer software look at cdrecord
+  (http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html)
+  and for burning a "disk at once": cdrdao
+  (http://www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high
+  quality digital reader of audio CDs (http://www.xiph.org/paranoia).
+  For other devices, it's possible that you'll have to write the
+  driver software yourself. Please read the file
+  Documentation/scsi-generic.txt for more information.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5858,6 +5931,15 @@
   The module will be called qlogicfc.o. If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
 
+Qlogic QLA 1280 SCSI support
+CONFIG_SCSI_QLOGIC_1280
+  Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called qla1280.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
 Seagate ST-02 and Future Domain TMC-8xx SCSI support
 CONFIG_SCSI_SEAGATE
   These are 8-bit SCSI controllers; the ST-01 is also supported by
@@ -6541,6 +6623,17 @@
   Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+PPP multilink support (EXPERIMENTAL)
+CONFIG_PPP_MULTILINK
+  PPP multilink is a protocol (defined in RFC 1990) which allows you
+  to combine several (logical or physical) lines into one logical PPP
+  connection, so that you can utilize your full bandwidth.
+
+  This has to be supported at the other end as well and you need a
+  version of the pppd daemon which understands the multilink protocol.
+
+  If unsure, say N.
+
 PPP support for async serial ports
 CONFIG_PPP_ASYNC
   Say Y (or M) here if you want to be able to use PPP over standard
@@ -6552,6 +6645,8 @@
   into and removed from the running kernel).  If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+  If unsure, say Y.
+
 PPP support for sync tty ports
 CONFIG_PPP_SYNC_TTY
   Say Y (or M) here if you want to be able to use PPP over synchronous
@@ -6902,15 +6997,16 @@
   as a module, say M here and read Documentation/modules.txt. If
   unsure, say N.
 
-3Com 3c575 CardBus support
-CONFIG_PCMCIA_3C575
-  This driver supports the 3Com 3c575 series of CardBus Fast Ethernet
-  adapters.
+IBM PCMCIA Token Ring adapter support
+CONFIG_PCMCIA_IBMTR
+  Say Y here if you intend to attach this type of Token Ring PCMCIA
+  card to your computer. You then also need to say Y to "Token Ring
+  driver support". 
 
-  This driver can only be compiled as a module ( = code which can be
+  This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will be called 3c575_cb.o. If you want to do that, say M
-  here and read Documentation/modules.txt.  If unsure, say N.
+  The module will be called ibmtr_cs.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 Xircom Tulip-like CardBus support
 CONFIG_PCMCIA_XIRTULIP
@@ -7216,7 +7312,7 @@
   Differentiated Services (diffserv) and Resource Reservation Protocol
   (RSVP) on your Linux router if you also say Y to "QoS support",
   "Packet classifier API" and to some classifiers below. Documentation
-  and software is at http://icawwww1.ipfl.ch/linux/diffserv/ .
+  and software is at http://icawww1.epfl.ch/linux-diffserv/ .
 
   If you say Y here and to "/proc file system" below, you will be able
   to read status information about packet schedulers from the file
@@ -7346,7 +7442,7 @@
   Differentiated Services (diffserv) and Resource Reservation Protocol
   (RSVP) on your Linux router if you also say Y to "Packet classifier
   API" and to some classifiers below. Documentation and software is at
-  http://icawwww1.ipfl.ch/linux/diffserv/ .
+  http://icawww1.epfl.ch/linux-diffserv/ .
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -7369,7 +7465,7 @@
   This will enable you to use Differentiated Services (diffserv) and
   Resource Reservation Protocol (RSVP) on your Linux router.
   Documentation and software is at
-  http://icawwww1.ipfl.ch/linux/diffserv/ .
+  http://icawww1.epfl.ch/linux-diffserv/ .
 
 ### Add
 #tristate '    TC index classifier' CONFIG_NET_CLS_TCINDEX
@@ -7492,6 +7588,31 @@
   The module will be called cosa.o. For general information about
   modules read Documentation/modules.txt.
 
+Lan Media sync serial boards support
+CONFIG_LANMEDIA
+  This is a driver for the following Lan Media family of serial boards.
+ 
+  LMC 1000 board allows you to connect synchronous serial devices (for
+  example base-band modems, or any other device with the X.21, V.24,
+  V.35 or V.36 interface) to your Linux box.
+ 
+  LMC 1200 with on board DSU board allows you to connect your Linux
+  box dirrectly to a T1 or E1 circuit.
+ 
+  LMC 5200 board provides a HSSI interface capable of runnig up to
+  52 mbits per second.
+ 
+  LMC 5245 board connects directly to a T3 circuit saving the
+  additional external hardware.
+ 
+  To change setting such as syncPPP vs cisco HDLC or clock source you
+  will need lmcctl.  It it available at ftp.lanmedia.com.
+ 
+  This code is also available as a module called lmc.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
 Fibre Channel driver support
 CONFIG_NET_FC
   Fibre Channel is a high speed serial protocol mainly used to connect
@@ -8163,12 +8284,19 @@
   Documentation/networking/net-modules.txt. The module will be called
   3c515.o.
 
-3c590 series (592/595/597) "Vortex" support
+3c59x/3c90x/3c575_Cardbus series "Vortex/Boomerang/Cyclone" support
 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 from
-  http://www.linuxdoc.org/docs.html#howto . More specific
+  This option enables driver support for a large number of 10mbps and
+  10/100mbps EISA, PCI and PCMCIA 3Com network cards:
+
+  "Vortex"    (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
+  "Boomerang" (EtherLink XL 3c900 or 3c905)            PCI
+  "Cyclone"   (3c540/3c900/3c905/3c980/3c575/3c656)    PCI and Cardbus
+  "Tornado"   (3c905)                                  PCI
+  "Hurricane" (3c555/3cSOHO)                           PCI
+
+  If you have such a card, say Y and read the Ethernet-HOWTO, available
+  from http://www.linuxdoc.org/docs.html#howto . More specific
   information is in Documentation/networking/vortex.txt and in the
   comments at the beginning of drivers/net/3c59x.c.
 
@@ -9357,11 +9485,13 @@
   modems, and printers support the USB protocol and can be connected
   to the PC via those ports.
 
-  Say Y here if your computer has a USB port and you want to
-  use USB devices. You then need to say Y to at least one
-  of "UHCI support" or "OHCI support" below (the type of interface
-  that the USB hardware in your computer provides) and then choose
-  from among the drivers for USB peripherals.
+  Say Y here if your computer has a USB port and you want to use USB
+  devices. You then need to say Y to at least one of "UHCI support" or
+  "OHCI support" below (the type of interface that the USB hardware in
+  your computer provides to the operating system) and then choose from
+  among the drivers for USB peripherals. You may want to check out the
+  information provided in Documentation/usb/ and especially the links
+  given in Documentation/usb/usb-help.txt.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -9370,8 +9500,8 @@
 
 USB verbose debug messages
 CONFIG_USB_DEBUG
-  Say Y here if you want the USB core drivers to produce a bunch of
-  debug messages to the system log. Select this if you are having a
+  Say Y here if you want the USB core & hub drivers to produce a bunch
+  of debug messages to the system log. Select this if you are having a
   problem with USB support and want to see more of what is going on.
 
 UHCI (intel PIIX4, VIA, ...) support?
@@ -9379,56 +9509,54 @@
   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 (like
-  intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard.
-  Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo
-  Pro II or Apollo Pro 133).
-  If unsure, say Y.
+  standard, you may want to say Y, but see below. All recent boards
+  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
+  i810, i820) conform to this standard. Also all VIA PCI chipsets
+  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
+  133).
+
+  Currently there exist two drivers for UHCI host controllers: this
+  one and the so-called JE driver, which you can get from 
+  "UHCI alternate (JE) support", below. You need only one.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called usb-uhci.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
-  
-USB-UHCI High Bandwidth support
-CONFIG_USB_UHCI_HIGH_BANDWIDTH
-  This option enables the so-called reclamation loop in usb-uhci, thus
-  allowing much higher transfer bandwidth for USB-bulk and control
-  messages; isochronous transfers (audio, video etc.) are not affected.
-  Due to a very simple design of the UHCI controller, this may cause
-  a significant PCI congestion under certain conditions. If you are
-  experiencing a system slowdown, disable this option.
-  
-  If unsure, say N.
-  
+
 UHCI (intel PIIX4, VIA, ...) alternate (JE) support?
 CONFIG_USB_UHCI_ALT
-  This is an alternate driver for UHCI support. It has been commonly
-  been referred to as the "JE driver".
-
   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 (like
-  intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard.
-  Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo
-  Pro II or Apollo Pro 133).
-  If unsure, say Y.
+  standard, you may want to say Y, but see below. All recent boards
+  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
+  i810, i820) conform to this standard. Also all VIA PCI chipsets
+  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
+  133). If unsure, say Y.
+
+  Currently there exist two drivers for UHCI host controllers: this
+  so-called JE driver, and the one you get from "UHCI support", above.
+  You need only one.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called uhci.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
-  
-OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support?
+
+UHCI unlink optimizations (EXPERIMENTAL)
+CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
+  This option currently does nothing. You may say Y or N.
+
+OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support
 CONFIG_USB_OHCI
   The Open Host Controller Interface is a standard by
   Compaq/Microsoft/National for accessing the USB PC hardware (also
-  called USB host controller). If your USB host controller conforms
-  to this standard, say Y. The USB host controllers on most
-  non-Intel architectures and on several x86 compatibles with non-Intel
-  chipsets - like SiS (actual 610, 610 and so on) or ALi (ALi IV, ALi V,
-  Aladdin Pro..) - conform to this standard.
+  called USB host controller). If your USB host controller conforms to
+  this standard, say Y. The USB host controllers on most non-Intel
+  architectures and on several x86 compatibles with non-Intel chipsets
+  -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V,
+  Aladdin Pro..) -- conform to this standard.
 
   You may want to read the file Documentation/usb/ohci.txt.
 
@@ -9439,9 +9567,17 @@
 
 USB Human Interface Device (HID) support
 CONFIG_USB_HID
-  Say Y here if you want to connect a keyboard, mouse, joystick,
-  graphic tablet, UPS or any other HID based devices to your computer
-  via USB.
+  Say Y here if you want to connect keyboards, mice, joysticks,
+  graphic tablets, UPS's or any other HID based devices to your
+  computer via USB. More information is available:
+  Documentation/usb/input.txt.
+
+  If unsure, say Y.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called hid.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 USB HIDBP Keyboard support
 CONFIG_USB_KBD
@@ -9515,17 +9651,6 @@
   The module will be called mousedev.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-Mix all mice into one device
-CONFIG_INPUT_MOUSEDEV_MIX
-  Say Y here if you want input from all your USB HID mice to be mixed
-  into one misc device. If you say N, you'll have a separate
-  device for each USB mouse.
-
-Support for digitizers
-CONFIG_INPUT_MOUSEDEV_DIGITIZER
-  Say Y here if you have a digitizer that doesn't emulate a mouse
-  itself, and want to use it as a mouse.
-
 Horizontal screen resolution
 CONFIG_INPUT_MOUSEDEV_SCREEN_X
   For the mouse emulation to be correct, the mousedev driver needs to
@@ -9578,6 +9703,7 @@
 CONFIG_USB_ACM
   This driver supports USB modems and ISDN adapters which support the
   Communication Device Class Abstract Control Model interface.
+  Please read Documentation/usb/acm.txt for details.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -9623,26 +9749,35 @@
 USB FTDI Single Port Serial Driver
 CONFIG_USB_SERIAL_FTDI_SIO
   Say Y here if you want to use a FTDI SIO single port USB to serial
-  converter device. The implementation I have is called the USC-1000
+  converter device. The implementation I have is called the USC-1000.
 
-  See http://reality.sgi.com/bryder_wellington/ftdi_sio for more information 
-   on this driver and the device
+  See http://reality.sgi.com/bryder_wellington/ftdi_sio for more
+  information on this driver and the device.
 
-USB FTDI Single Port Serial Driver
+USB Keyspan PDA Single Port Serial Driver
 CONFIG_USB_SERIAL_KEYSPAN_PDA
-  Say Y here if you want to use a Keyspan PDA single port USB to serial
-  converter device.
+  Say Y here if you want to use a Keyspan PDA single port USB to
+  serial converter device.
+
+USB ZyXEL omni.net LCD Plus Driver
+CONFIG_USB_SERIAL_OMNINET
+  Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA.
 
 USB Printer support
 CONFIG_USB_PRINTER
-  Say Y here if you want to connect a USB printer to your computer's USB
-  port.
+  Say Y here if you want to connect a USB printer to your computer's
+  USB port.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called printer.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+USB Serial Converter verbose debug
+CONFIG_USB_SERIAL_DEBUG
+  Say Y here if you want verbose debug messages from the USB Serial
+  Converter. 
+
 USB IBM (Xirlink) C-It Camera support
 CONFIG_USB_IBMCAM
   Say Y here if you want to connect a IBM "C-It" camera, also known as
@@ -9710,13 +9845,12 @@
   The module will be called dc2xx.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-
 USB Mustek MDC800 Digital Camera Support
 CONFIG_USB_MDC800
   Say Y here if you want to connect this type of still camera to
   your computer's USB port. This driver can be used with gphoto 0.4.3
-  and higher (look at www.gphoto.org).
-  To use it create a devicenode with mknod /dev/mustek c 180 32 and
+  and higher (look at http://www.gphoto.org ).
+  To use it create a device node with "mknod /dev/mustek c 10 171" and
   configure it in your software.
 
   This code is also available as a module ( = code which can be
@@ -9771,13 +9905,13 @@
 CONFIG_USB_DEVICEFS
   If you say Y here (and to "/proc file system support" below), you
   will get a file /proc/usb/devices which lists the devices currently
-  connected to your USB busses, a file /proc/usb/drivers file which
-  lists the USB kernel client drivers currently loaded, and for every
+  connected to your USB busses, a file /proc/usb/drivers which lists
+  the USB kernel client drivers currently loaded, and for every
   connected device a file named "/proc/usb/xxx/yyy", where xxx is the
   bus number and yyy the device number; the latter files can be used
-  by userspace drivers to talk to the device. These files are
-  "virtual", meaning they are generated on the fly and not stored on
-  the hard drive.
+  by user space programs to talk directly to the device. These files
+  are "virtual", meaning they are generated on the fly and not stored
+  on the hard drive.
   
   For the format of the /proc/usb/ files, please read
   Documentation/usb/proc_usb_info.txt. 
@@ -9939,8 +10073,33 @@
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. The module will be
-  called cramfs.o.
+  called cramfs.o. Note that the root file system (the one containing
+  the directory /) cannot be compiled as a module.
+
+  If unsure, say N.
    
+Simple RAM-based file system support
+CONFIG_RAMFS
+  Ramfs is a file system which keeps all files in RAM. It allows
+  read and write access.
+
+  In contrast to RAM disks, which get allocated a fixed amount of RAM,
+  ramfs grows and shrinks to accommodate the files it contains.
+
+  Before you can use this RAM-based file system, it has to be mounted,
+  meaning it has to be given a location in the directory hierarchy. If
+  you want to use the location /ramfiles for example, you would have
+  to create that directory first and then mount the file system by
+  saying "mount -t ramfs ramfs /ramfiles" or the equivalent line in
+  /etc/fstab. Everything is "virtual" in the sense that no files will
+  be created on your hard drive; if you reboot, everything in
+  /ramfiles will be lost.
+  
+  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 ramfs.o.
+
 ISO 9660 CDROM file system support
 CONFIG_ISO9660_FS
   This is the standard file system used on CDROMs. It was previously
@@ -10124,12 +10283,17 @@
   (there is a small number of Interrupt ReQuest lines in your computer
   that are used by the attached devices to gain the CPU's attention --
   often a source of trouble if two devices are mistakenly configured
-  to use the same IRQ). 
+  to use the same IRQ). The program procinfo to display some
+  information about your system gathered from the /proc file system.
+
+  Before you can use the /proc file system, it has to be mounted,
+  meaning it has to be given a location in the directory hierarchy.
+  That location should be /proc. A command such as "mount -t proc proc
+  /proc" or the equivalent line in /etc/fstab does the job.
 
   The /proc file system is explained in the file
   Documentation/filesystems/proc.txt and on the proc(5) manpage ("man
-  5 proc"). You can also use the program procinfo to display some
-  information about your system gathered from the /proc file system.
+  5 proc").
 
   This option will enlarge your kernel by about 67 KB. Several
   programs depend on this, so everyone should say Y here.
@@ -10142,9 +10306,9 @@
   allocations. Device drivers register entries in /dev which then
   appear automatically, which means that the system administrator does
   not have to create character and block special device files in the
-  /dev directory using the mknod command anymore.
+  /dev directory using the mknod command (or MAKEDEV script) anymore.
 
-  This is work in progress. If you want to use this you *must* read
+  This is work in progress. If you want to use this, you *must* read
   the material in Documentation/filesystems/devfs/, especially the
   file README there.
 
@@ -10193,6 +10357,13 @@
 
   If you don't know what all this is about, say N.
 
+Provide NFSv3 client support (EXPERIMENTAL)
+CONFIG_NFS_V3
+  Say Y here if you want your NFS client to be able to speak the newer
+  version 3 of the NFS protocol. 
+ 
+  If unsure, say N.
+
 Root file system on NFS
 CONFIG_ROOT_NFS
   If you want your Linux box to mount its whole root file system (the
@@ -10219,6 +10390,10 @@
   locations are given in the file Documentation/Changes in the NFS
   section.
 
+  If you say Y here, you will get support for version 2 of the NFS
+  protocol (NFSv2). If you also want NFSv3, say Y to the next question
+  as well.
+
   Please read the NFS-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto .
 
@@ -10265,7 +10440,7 @@
   If you say Y here, you will (maybe) be able to write to NTFS file
   systems as well as read from them. The read-write support in
   NTFS is far from being complete and is not well tested. If you
-  enable this, back up your NTFS volume first since it may get
+  say Y here, back up your NTFS volume first since it may get
   damaged. Also, make sure to run chkdsk from within Microsoft
   Windows NT after having performed any writes to a NTFS partition
   from Linux to detect any problems as early as possible.
@@ -10361,7 +10536,8 @@
   which can be inserted in and removed from the running kernel
   whenever you want). The module is called romfs.o. If you want to
   compile it as a module, say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt. Note that the file system of your root
+  partition (the one containing the directory /) cannot be a module.
 
   If you don't know whether you need it, then you don't need it:
   answer N.
@@ -10393,9 +10569,9 @@
   overhead in the already-mounted case; this is unlike the BSD
   automounter (amd), which is a pure user space daemon.
 
-  To use the automounter you need the user-space tools from
-  ftp://ftp.kernel.org/pub/linux/daemons/autofs ; you also want to
-  answer Y to "NFS file system support", below.
+  To use the automounter you need the user-space tools from the autofs
+  package; you can find the location in Documentation/Changes. You
+  also want to answer Y to "NFS file system support", below.
 
   If you want to use the newer version of the automounter with more
   features, say N here and say Y to "Kernel automounter v4 support",
@@ -10585,7 +10761,8 @@
 
   The GNU C library glibc 2.1 contains the requisite support for this
   mode of operation; you also need client programs that use the Unix98
-  API.
+  API. Please read Documentation/Changes for more information about
+  the Unix98 pty devices.
 
   Note that the experimental "/dev file system support"
   (CONFIG_DEVFS_FS)  is a more general facility.
@@ -12336,14 +12513,30 @@
 CONFIG_WDT
   If you have a WDT500P or WDT501P watchdog board, say Y here,
   otherwise N. It is not possible to probe for this board, which means
-  that you have to set the IO port and IRQ it uses in the kernel
-  source at the top of drivers/char/wdt.c. 
+  that you have to inform the kernel about the IO port and IRQ using
+  the "wdt=" kernel option (try "man bootparam" or see the
+  documentation of your boot loader (lilo or loadlin) about how to
+  pass options to the kernel at boot time).
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. The module will be
   called wdt.o.
 
+WDT PCI Watchdog timer
+CONFIG_WDTPCI
+  If you have a PCI WDT500/501 watchdog board, say Y here,
+  otherwise N. It is not possible to probe for this board, which means
+  that you have to inform the kernel about the IO port and IRQ using
+  the "wdt=" kernel option (try "man bootparam" or see the
+  documentation of your boot loader (lilo or loadlin) about how to
+  pass options to the kernel at boot time).
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called wdt_pci.o.
+
 WDT501 features
 CONFIG_WDT_501
   Saying Y here and creating a character special file /dev/temperature
@@ -12836,9 +13029,9 @@
 ProAudioSpectrum 16 support
 CONFIG_SOUND_PAS
   Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
-  16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
-  some other card made by Media Vision or Logitech since they are not
-  PAS16 compatible.
+  16 or Logitech SoundMan 16 sound card. Answer N if you have some
+  other card made by Media Vision or Logitech since those are not
+  PAS16 compatible. Please read Documentation/sound/PAS16.
 
   If you compile the driver into the kernel, you have to add
   "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
@@ -12854,12 +13047,12 @@
   Please read the file Documentation/sound/Soundblaster.
 
   You should also say Y here for cards based on the Avance Logic
-  ALS-007 chip (read Documentation/sound/ALS) and for cards based
-  on ESS chips (read Documentation/sound/ESS1868 and
+  ALS-007 and ALS-1X0 chips (read Documentation/sound/ALS) and for cards
+  based on ESS chips (read Documentation/sound/ESS1868 and
   Documentation/sound/ESS). If you have an SB AWE 32 or SB AWE 64, say
-  Y here and also to "Additional lowlevel drivers" and to "SB32/AWE
-  support" below and read Documentation/sound/INSTALL.awe. If you have
-  an IBM Mwave card, say Y here and read Documentation/sound/mwave.
+  Y here and also to "AWE32 synth" below and read 
+  Documentation/sound/INSTALL.awe. If you have an IBM Mwave card, say
+  Y here and read Documentation/sound/mwave.
 
   If you compile the driver into the kernel and don't want to use
   isapnp, you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel
@@ -13248,6 +13441,11 @@
   driver as a module you have to specify the MPU I/O base address with
   the parameter 'mpu_base=0xNNN'.
 
+Creative EMU10K1 based PCI sound cards
+CONFIG_SOUND_EMU10K1
+  Say Y or M if you have a PCI sound card using the EMU10K1
+  chipset, such as the Creative SBLive! or SB PCI512.
+
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
@@ -13494,9 +13692,8 @@
   Say Y or N according to the D-channel protocol which your local
   telephone service company provides.
 
-  NOTE: If you say Y here and you have only one ISDN card installed,
-  you cannot say Y to "HiSax Support for German 1TR6", below. And vice
-  versa.
+  The call control protocol E-DSS1 is used in most European countries.
+  If unsure, say yes.
 
 Support for german charge info
 CONFIG_DE_AOC
@@ -13527,9 +13724,9 @@
   Say Y or N according to the D-channel protocol which your local
   telephone service company provides.
 
-  NOTE: If you say Y here and you have only one ISDN card installed,
-  you cannot say Y to "HiSax Support for EURO/DSS1", above. And vice
-  versa.
+  1TR6 is an old call control protocol which was used in Germany
+  before E-DSS1 was established. Nowadays, all new lines in Germany
+  use E-DSS1.
 
 Teles 16.0/8.0
 CONFIG_HISAX_16_0
@@ -14932,6 +15129,35 @@
   as a module (c-qcam.o). Read Documentation/video4linux/CQcam.txt for
   more information.
 
+CPiA Video For Linux
+CONFIG_VIDEO_CPIA
+  This is the video4linux driver for cameras based on Vision's CPiA
+  (Colour Processor Interface ASIC), such as the Creative Labs Video
+  Blaster Webcam II. If you have one of these cameras, say Y here
+  and select parallel port and/or USB lowlevel support below,
+  otherwise say N. This will not work with the Creative Webcam III.
+  
+  Please read Documentation/video4linux/README.cpia for more
+  information.
+  
+  This driver is also available as a module (cpia.o).
+
+CPiA Parallel Port Lowlevel Support
+CONFIG_VIDEO_CPIA_PP
+  This is the lowlevel parallel port support for cameras based on
+  Vision's CPiA (Colour Processor Interface ASIC), such as the
+  Creative Webcam II. If you have the parallel port version of one
+  of these cameras, say Y here, otherwise say N. It is also available
+  as a module (cpia_pp.o).
+
+CPiA USB Lowlevel Support
+CONFIG_VIDEO_CPIA_USB
+  This is the lowlevel USB support for cameras based on Vision's CPiA
+  (Colour Processor Interface ASIC), such as the Creative Webcam II.
+  If you have the USB version of one of these cameras, say Y here,
+  otherwise say N. This will not work with the Creative Webcam III.
+  It is also available as a module (cpia_usb.o).
+
 Mediavision Pro Movie Studio Video For Linux
 CONFIG_VIDEO_PMS
   Say Y if you have such a thing. This driver is also available as a
@@ -15410,121 +15636,16 @@
   boards from BVM Ltd.  Everyone using one of these boards should say
   Y here.
 
-Support for user-space parallel port device drivers
-CONFIG_PPDEV
-  Saying Y to this adds support for /dev/parport device nodes.  This
-  is needed for programs that want portable access to the parallel
-  port, for instance deviceid (which displays Plug-and-Play device
-  IDs).
-
-  This is the parallel port equivalent of SCSI generic support (sg).
-  It is safe to say N to this -- it is not needed for normal printing
-  or parallel port CD-ROM/disk support.
-
-  This support is also available as a module. If you want to compile
-  it as a module, say M here and read Documentation/modules.txt. The
-  module will be called ppdev.o.
-
-  If unsure, say N.
-
-Kernel httpd acceleration (EXPERIMENTAL)
-CONFIG_KHTTPD
-  The kernel httpd acceleration daemon (kHTTPd) is a (limited) 
-  web server build into the kernel. It is limited since it can only
-  serve files from the file system. Saying "M" here builds the
-  kHTTPd module; this is NOT enough to have a working kHTTPd. 
-  For safety reasons, the module has to be activated by doing a
-  "echo 1 > /proc/sys/net/khttpd/start" after inserting the module.
-
-  Before using this, read the README in /usr/src/linux/net/khttpd !
-
-  The kHTTPd is experimental. Be careful when using it on a production
-  machine. Also note that kHTTPd doesn't support virtual servers yet.
-
-I2C support
-CONFIG_I2C
-  I2C (pronounce: I-square-C) is a slow bus protocol developed by
-  Philips. SMBus, or System Management Bus is a sub-protocol of I2C.
-
-  Both I2C and SMBus are supported here. You will need this for 
-  hardware sensors support, and in the future for Video for Linux
-  support.
-
-  Beside this option, you will also need to select specific drivers 
-  for your bus adapter(s). 
-
-I2C bit-banging interfaces
-CONFIG_I2C_ALGOBIT
-  This allows you to use a range of I2C adapters called bit-banging
-  adapters. Why they are called so is rather technical and uninteresting;
-  but you need to select this if you own one of the adapters listed
-  under it.
-
-Philips style parallel port adapter
-CONFIG_I2C_PHILIPSPAR
-  This supports parallel-port I2C adapters made by Philips. Unless you
-  own such an adapter, you do not need to select this.
-
-ELV adapter
-CONFIG_I2C_ELV
-  This supports parallel-port I2C adapters called ELV. Unless you 
-  own such an adapter, you do not need to select this.
-
-Velleman K9000 adapter
-CONFIG_I2C_VELLEMAN
-  This supports the Velleman K9000 parallel-port I2C adapter. Unless
-  you own such an adapter, you do not need to select this.
-
-I2C PCF 8584 interfaces
-CONFIG_I2C_ALGOPCF
-  This allows you to use a range of I2C adapters called PCF
-  adapters. Why they are called so is rather technical and uninteresting;
-  but you need to select this if you own one of the adapters listed
-  under it.
-
-Elektor ISA card
-CONFIG_I2C_ELEKTOR
-  This supports the PCF8584 ISA bus I2C adapter. Unless you own such
-  an adapter, you do not need to select this.
-
-I2C device interface
-CONFIG_I2C_CHARDEV
-  Here you find the drivers which allow you to use the i2c-* device 
-  files, usually found in the /dev directory on your system. They
-  make it possible to have user-space programs use the I2C bus.
-
-CPiA Video For Linux
-CONFIG_VIDEO_CPIA
-  This is the video4linux driver for cameras based on Vision's CPiA
-  (Colour Processor Interface ASIC), such as the Creative Labs Video
-  Blaster Webcam II. If you have one of these cameras, say Y here
-  and select parallel port and/or USB lowlevel support below,
-  otherwise say N. This will not work with the Creative Webcam III.
-  It is also available as a module (cpia.o).
-
-CPiA Parallel Port Lowlevel Support
-CONFIG_VIDEO_CPIA_PP
-  This is the lowlevel parallel port support for cameras based on
-  Vision's CPiA (Colour Processor Interface ASIC), such as the
-  Creative Webcam II. If you have the parallel port version of one
-  of these cameras, say Y here, otherwise say N. It is also available
-  as a module (cpia_pp.o).
-
-CPiA USB Lowlevel Support
-CONFIG_VIDEO_CPIA_USB
-  This is the lowlevel USB support for cameras based on Vision's CPiA
-  (Colour Processor Interface ASIC), such as the Creative Webcam II.
-  If you have the USB version of one of these cameras, say Y here,
-  otherwise say N. This will not work with the Creative Webcam III.
-  It is also available as a module (cpia_usb.o).
 
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
-#               Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS, 
-#               PCI, SCSI, SPARC
-#   two words:  hard drive, hard disk, sound card, home page
-#   other:      it's safe to save; daemon; use --, not - or ---
+#               Intel, IRQ, ISDN, Linux, MSDOS, NetWare, NetWinder, 
+#               NFS, PCI, SCSI, SPARC
+#   two words:  file system, hard drive, hard disk, home page, 
+#               user space, web site
+#   other:      it's safe to save; daemon; use --, not - or ---;
+#               use KB for 1024 bytes, not kB or K.
 #
 #
 # This is used by Emacs' spell checker ispell.el:
@@ -15655,7 +15776,7 @@
 # LocalWords:  caldera Preload Preloading slowdowns schoebel uni NBD nbd prog
 # LocalWords:  stuttgart rdist TRANS hostnames mango jukeboxes ESS userland PD
 # LocalWords:  hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid
-# LocalWords:  filespace adm Nodename hostname uname Kernelname bootp nmi DI OV
+# LocalWords:  adm Nodename hostname uname Kernelname bootp nmi DI OV StegFS
 # LocalWords:  KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb
 # LocalWords:  dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS
 # LocalWords:  nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
@@ -15803,7 +15924,7 @@
 # LocalWords:  Diffserv DSMARK Ingress Qdisc TCINDEX TMSPCI tmspci Ringode JE
 # LocalWords:  MADGEMC madgemc TokenRing SMCTR TokenCard smctr Wacom Graphire
 # LocalWords:  WMFORCE mousedev ConnectTech HandSpring Xirlink IBMCAM ibmcam SN
-# LocalWords:  DEVICEFS yyy userspace Cymraeg Dwave SIMM JSFLASH JavaStation's
+# LocalWords:  DEVICEFS yyy Cymraeg Dwave SIMM JSFLASH JavaStation's multilink
 # LocalWords:  nsc ircc DDB Vrc CMN TB PROMs Vino rivafb DDC Matroxes MGA TVO
 # LocalWords:  MAVEN fbdev crtc maven matroxset NTSC PCA SBA AAL SKFP DAS SAS
 # LocalWords:  skfp Intuos ADMtek's pegasus PLUSB plusb pointopoint mp rio Xeon
@@ -15828,4 +15949,7 @@
 # LocalWords:  UltraDMA WDC CRC CONNTRACK IPTABLES iptables nfmark interface's
 # LocalWords:  tdfxfb TNTx HGA hgafb VERBOSEDEBUG SunTrunking SunSoft XIRTULIP
 # LocalWords:  ethercards PNIC Macronix MXIC ASIX xircom Mustek MDC gphoto mdc
-# LocalWords:  CramFs Cramfs uid cramfs AVM's kernelcapi PCIV
+# LocalWords:  CramFs Cramfs uid cramfs AVM's kernelcapi PCIV cdrdao Cdparanoia
+# LocalWords:  DMX Domex dmx wellington ftdi sio Accton Billington Corega FEter
+# LocalWords:  MELCO LUA PNA Linksys SNC chkdsk AWACS Webcam RAMFS Ramfs ramfs
+# LocalWords:  ramfiles MAKEDEV pty WDTPCI APA apa
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- v2.3.99-pre5/linux/Documentation/DMA-mapping.txt	Sun Feb 20 21:12:38 2000
+++ linux/Documentation/DMA-mapping.txt	Tue Apr 25 17:52:05 2000
@@ -198,7 +198,7 @@
 PCI_DMA_TODEVICE means "from main memory to the PCI device"
 PCI_DMA_FROMDEVICE means "from the PCI device to main memory"
 
-Cou are _strongly_ encouraged to specify this as precisely
+You are _strongly_ encouraged to specify this as precisely
 as you possibly can.
 
 If you absolutely cannot know the direction of the DMA transfer,
@@ -284,7 +284,7 @@
 
 To unmap a scatterlist, just call:
 
-	pci_unmap_sg(dev, sglist, nents);
+	pci_unmap_sg(dev, sglist, nents, direction);
 
 Again, make sure DMA activity finished.
 
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile
--- v2.3.99-pre5/linux/Documentation/DocBook/Makefile	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/DocBook/Makefile	Thu Apr 13 09:25:44 2000
@@ -3,13 +3,22 @@
 PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
 PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
 
-books:	docproc $(BOOKS)
+$(BOOKS): $(TOPDIR)/scripts/docproc
+
+.PHONY:	books ps pdf clean mrproper db2ps db2pdf
+
+books:	$(BOOKS)
 
 ps:	$(PS)
 
 pdf:	$(PDF)
 
-docproc:
+db2ps db2pdf:
+	@(which $@ > /dev/null 2>&1) || \
+	 (echo "*** You need to install DocBook stylesheets ***"; \
+	  exit 1)
+
+$(TOPDIR)/scripts/docproc:
 	$(MAKE) -C $(TOPDIR)/scripts docproc
 
 wanbook.sgml: wanbook.tmpl
@@ -64,7 +73,7 @@
 mrproper: clean
 	$(RM) $(PS) $(PDF)
 
-%.ps : %.sgml
+%.ps : %.sgml db2ps
 	db2ps $<
 
 %.pdf : %.sgml
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/arm/Setup linux/Documentation/arm/Setup
--- v2.3.99-pre5/linux/Documentation/arm/Setup	Fri Oct 22 13:21:43 1999
+++ linux/Documentation/arm/Setup	Tue Apr 25 17:38:33 2000
@@ -112,6 +112,14 @@
 
    system 64-bit serial number
 
+ mem_fclk_21285
+
+   The speed of the external oscillator to the 21285 (footbridge),
+   which control's the speed of the memory bus, timer & serial port.
+   Depending upon the speed of the cpu its value can be between
+   0-66 MHz. If no params are passed or a value of zero is passed,
+   then a value of 50 Mhz is the default on 21285 architectures.
+
  paths[8][128]
 
    These are now obsolete, and should not be used.
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/computone.txt linux/Documentation/computone.txt
--- v2.3.99-pre5/linux/Documentation/computone.txt	Fri Jan 21 18:19:15 2000
+++ linux/Documentation/computone.txt	Tue Apr 25 16:53:13 2000
@@ -6,12 +6,12 @@
 These notes are for the drivers which have already been integrated into the
 kernel and have been tested on Linux kernels 2.0, 2.2, and 2.3.
 
-Version: 1.2.4
-Date: 12/15/99
+Version: 1.2.9
+Date: 04/12/2000
 Author: Andrew Manison <amanison@america.net>
 Testing: larryg@computone.com
 Support: support@computone.com
-Fixes and Updates: Doug McNash <dmcnash@computone.com>
+Fixes and Updates: Doug McNash <dougm@computone.com>
 Proc Filesystem and Kernel Integration: Mike Warfield <mhw@wittsend.com>
 
 
@@ -28,7 +28,7 @@
 products previous to the Intelliport II.
 
 This driver was developed on the v2.0.x Linux tree and has been tested up
-to v2.2.13; it will probably not work with earlier v1.X kernels,.
+to v2.2.14; it will probably not work with earlier v1.X kernels,.
 
 
 2. QUICK INSTALLATION
@@ -43,49 +43,48 @@
 
 	Note the hardware address from the Computone ISA cards installed into
 		the system.  These are required for editing ip2.h or editing
-		/etc/config.modules, or for specification on the modprobe
+		/etc/modules.conf, or for specification on the modprobe
 		command line.
 
+	Note that the /etc/modules.conf file is named /etc/conf.modules
+		with older versions of the module utilities.
+
 Software -
 
 Module installation:
 
-a) Obtain driver-kernel patch file
-b) Copy to the linux source tree root, Run ip2build (if not patch)
-c) Determine free irq/address to use if any (configure BIOS if need be)
-d) Run "make config" or "make menuconfig" or "make xconfig"
+a) Determine free irq/address to use if any (configure BIOS if need be)
+b) Run "make config" or "make menuconfig" or "make xconfig"
    Select (m) module for CONFIG_COMPUTONE under character
    devices.  CONFIG_PCI and CONFIG_MODULES also may need to be set.
-e) Set address on ISA cards then:
+c) Set address on ISA cards then:
    edit /usr/src/linux/drivers/char/ip2/ip2.h if needed 
 	or
    edit /etc/modules.conf if needed (module).
 	or both to match this setting.
-f) Run "make dep"
-g) Run "make modules"
-h) Run "make modules_install"
-i) Run "/sbin/depmod -a"
-j) install driver using `modprobe ip2 <options>` (options listed below)
-k) run ip2mkdev (either the script below or the binary version)
+d) Run "make dep"
+e) Run "make modules"
+f) Run "make modules_install"
+g) Run "/sbin/depmod -a"
+h) install driver using `modprobe ip2 <options>` (options listed below)
+i) run ip2mkdev (either the script below or the binary version)
 
 
 Kernel installation:
 
-a) Obtain driver-kernel patch file
-b) Copy to the linux source tree root, Run ip2build (if not patch)
-c) Determine free irq/address to use if any (configure BIOS if need be)
-d) Run "make config" or "make menuconfig" or "make xconfig"
+a) Determine free irq/address to use if any (configure BIOS if need be)
+b) Run "make config" or "make menuconfig" or "make xconfig"
    Select (y) kernel for CONFIG_COMPUTONE under character
    devices.  CONFIG_PCI may need to be set if you have PCI bus.
-e) Set address on ISA cards then:
+c) Set address on ISA cards then:
 	   edit /usr/src/linux/drivers/char/ip2/ip2.h  
-f) Run "make dep"
-g) Run "make zImage" or whatever target you prefer.
-h) mv /usr/src/linux/arch/i386/boot/zImage to /boot.
-i) Add new config for this kernel into /etc/lilo.conf, run "lilo"
+d) Run "make dep"
+e) Run "make zImage" or whatever target you prefer.
+f) mv /usr/src/linux/arch/i386/boot/zImage to /boot.
+g) Add new config for this kernel into /etc/lilo.conf, run "lilo"
 	or copy to a floppy disk and boot from that floppy disk.
-j) Reboot using this kernel
-k) run ip2mkdev (either the script below or the binary version)
+h) Reboot using this kernel
+i) run ip2mkdev (either the script below or the binary version)
 
 
 3. INSTALLATION
@@ -162,6 +161,22 @@
 Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
 cuf0 - cuf255 for callout devices.
 
+If you are using devfs, existing devices are automatically created within
+the devfs name space.  Normal devices will be ttf/0 - ttf/255 and callout
+devices will be cuf/0 - cuf/255.  With devfs installed, ip2mkdev will
+create symbolic links in /dev from the old conventional names to the newer
+devfs names as follows:
+
+	/dev/ip2ipl[n]	-> /dev/ip2/ipl[n]	n = 0 - 3
+	/dev/ip2stat[n]	-> /dev/ip2/stat[n]	n = 0 - 3
+	/dev/ttyF[n]	-> /dev/ttf/[n]		n = 0 - 255
+	/dev/cuf[n]	-> /dev/cuf/[n]		n = 0 - 255
+
+Only devices for existing ports and boards will be created.
+
+You do not need to run ip2mkdev if you are using devfs and only want to
+use the devfs native device names.
+
 
 4. USING THE DRIVERS
 
@@ -195,14 +210,49 @@
 use the ip2mkdev script, you must have procfs enabled and the proc file
 system mounted on /proc.
 
-6. NOTES
+You do not need to run ip2mkdev if you are using devfs and only want to
+use the devfs native device names.
+
+
+6. DEVFS
+
+DEVFS is the DEVice File System available as an add on package for the
+2.2.x kernels and available as a configuration option in 2.3.46 and higher.
+Devfs allows for the automatic creation and management of device names
+under control of the device drivers themselves.  The Devfs namespace is
+hierarchial and reduces the clutter present in the normal flat /dev
+namespace.  Devfs names and conventional device names may be intermixed.
+A userspace daemon, devfsd, exists to allow for automatic creation and
+management of symbolic links from the devfs name space to the conventional
+names.  More details on devfs can be found on the DEVFS home site at
+<http://www.atnf.csiro.au/~rgooch/linux/> or in the file kernel
+documenation files, .../linux/Documenation/filesystems/devfs/REAME.
+
+If you are using devfs, existing devices are automatically created within
+the devfs name space.  Normal devices will be ttf/0 - ttf/255 and callout
+devices will be cuf/0 - cuf/255.  With devfs installed, ip2mkdev will
+create symbolic links in /dev from the old conventional names to the newer
+devfs names as follows:
+
+	/dev/ip2ipl[n]	-> /dev/ip2/ipl[n]	n = 0 - 3
+	/dev/ip2stat[n]	-> /dev/ip2/stat[n]	n = 0 - 3
+	/dev/ttyF[n]	-> /dev/ttf/[n]		n = 0 - 255
+	/dev/cuf[n]	-> /dev/cuf/[n]		n = 0 - 255
+
+Only devices for existing ports and boards will be created.
+
+You do not need to run ip2mkdev if you are using devfs and only want to
+use the devfs native device names.
+ 
+
+7. NOTES
 
 This is a release version of the driver, but it is impossible to test it
 in all configurations of Linux. If there is any anomalous behaviour that 
 does not match the standard serial port's behaviour please let us know.
 
 
-7. ip2mkdev shell script
+8. ip2mkdev shell script
 
 Previously, this script was simply attached here.  It is now attached as a
 shar archive to make it easier to extract the script from the documentation.
@@ -223,15 +273,15 @@
 # To extract the files from this archive, save it to some FILE, remove
 # everything before the `!/bin/sh' line above, then type `sh FILE'.
 #
-# Made on 1999-12-17 16:06 EST by <root@alcove.wittsend.com>.
-# Source directory was `/mnt2/src/linux-2.3.33/Documentation'.
+# Made on 2000-03-10 11:55 EST by <root@wittsend.wittsend.com>.
+# Source directory was `/mnt1/src/linux-2.3.50c/Documentation'.
 #
 # Existing files will *not* be overwritten unless `-c' is specified.
 #
 # This shar contains:
 # length mode       name
 # ------ ---------- ------------------------------------------
-#   3300 -rwxr-xr-x ip2mkdev
+#   4061 -rwxr-xr-x ip2mkdev
 #
 save_IFS="${IFS}"
 IFS="${IFS}:"
@@ -278,7 +328,7 @@
 fi
 rm -f 1231235999 $$.touch
 #
-if mkdir _sh06360; then
+if mkdir _sh17088; then
   $echo 'x -' 'creating lock directory'
 else
   $echo 'failed to create lock directory'
@@ -291,7 +341,7 @@
   $echo 'x -' extracting 'ip2mkdev' '(text)'
   sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' &&
 #!/bin/sh -
-X
+#
 #	ip2mkdev
 #
 #	Make or remove devices as needed for Computone Intelliport drivers
@@ -300,16 +350,48 @@
 #	with it.  That prevents us from screwing up open ttys, ownership
 #	and permissions on a running system!
 #
-#	This script will NOT remove devices that no longer exist because
-#	their board or interface box has been removed.  If you want to get
-#	rid of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
-#	before running this script, which will then recreate all the valid
-#	devices
+#	This script will NOT remove devices that no longer exist if their
+#	board or interface box has been removed.  If you want to get rid
+#	of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
+#	before running this script.  Running this script will then recreate
+#	all the valid devices.
 #
 #	=mhw=
 #	Michael H. Warfield
 #	mhw@wittsend.com
 #
+#	Updated 03/09/2000 for devfs support in ip2 drivers. =mhw=
+#
+X
+if test -d /dev/ip2 ; then
+#	This is devfs mode...  We don't do anything except create symlinks
+#	from the real devices to the old names!
+X	cd /dev
+X	echo "Creating symbolic links to devfs devices"
+X	for i in `ls ip2` ; do
+X		if test ! -L ip2$i ; then
+X			# Remove it incase it wasn't a symlink (old device)
+X			rm -f ip2$i
+X			ln -s ip2/$i ip2$i
+X		fi
+X	done
+X	for i in `ls ttf` ; do
+X		if test ! -L ttyF$i ; then
+X			# Remove it incase it wasn't a symlink (old device)
+X			rm -f ttyF$i
+X			ln -s ttyf/$i ttyF$i
+X		fi
+X	done
+X	for i in `ls cuf` ; do
+X		if test ! -L cuf$i ; then
+X			# Remove it incase it wasn't a symlink (old device)
+X			rm -f cuf$i
+X			ln -s cuf/$i cuf$i
+X		fi
+X	done
+X	exit 0
+fi
+X
 if test ! -f /proc/tty/drivers
 then
 X	echo "\
@@ -344,8 +426,8 @@
 # Ok...  So we got the driver loaded and we can locate the procfs files.
 # Next we need our major numbers.
 X
-TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tty/!d' -e 's/.*tty.[ 	]*\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/drivers`
-CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu.[ 	]*\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/drivers`
+TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ 	]*[ 	]*\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/drivers`
+CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ 	]*[ 	]*\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/drivers`
 BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ 	]*.*/\1/' < /proc/tty/driver/ip2`
 X
 echo "\
@@ -426,20 +508,20 @@
 X
 Xexit 0
 SHAR_EOF
-  $shar_touch -am 1217160599 'ip2mkdev' &&
+  $shar_touch -am 03101153100 'ip2mkdev' &&
   chmod 0755 'ip2mkdev' ||
   $echo 'restore of' 'ip2mkdev' 'failed'
   if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
   && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
     md5sum -c << SHAR_EOF >/dev/null 2>&1 \
     || $echo 'ip2mkdev:' 'MD5 check failed'
-eccd181f4a2005e47a969fc83885df61  ip2mkdev
+b0671abeba07b0a9266b70aaf24509b3  ip2mkdev
 SHAR_EOF
   else
     shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`"
-    test 3300 -eq "$shar_count" ||
-    $echo 'ip2mkdev:' 'original size' '3300,' 'current size' "$shar_count!"
+    test 4061 -eq "$shar_count" ||
+    $echo 'ip2mkdev:' 'original size' '4061,' 'current size' "$shar_count!"
   fi
 fi
-rm -fr _sh06360
+rm -fr _sh17088
 exit 0
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/fb/tgafb.txt linux/Documentation/fb/tgafb.txt
--- v2.3.99-pre5/linux/Documentation/fb/tgafb.txt	Thu Jul  1 10:57:36 1999
+++ linux/Documentation/fb/tgafb.txt	Wed Apr 12 09:47:30 2000
@@ -1,25 +1,35 @@
-[Also cloned from vesafb.txt, thanks to Gerd]
+$Id: tgafb.txt,v 1.1.2.2 2000/04/04 06:50:18 mato Exp $
 
 What is tgafb?
 ===============
 
 This is a driver for DECChip 21030 based graphics framebuffers, a.k.a. TGA
-cards, specifically the following models
+cards, which are usually found in older Digital Alpha systems. The
+following models are supported:
 
-ZLxP-E1 (8bpp, 4 MB VRAM)
+ZLxP-E1 (8bpp, 2 MB VRAM)
 ZLxP-E2 (32bpp, 8 MB VRAM)
 ZLxP-E3 (32bpp, 16 MB VRAM, Zbuffer)
 
-This version, tgafb-1.12, is almost a complete rewrite of the code written
-by Geert Uytterhoeven, which was based on the original TGA console code
-written by Jay Estabrook.
-
-Major new features:
-
- * Support for multiple resolutions, including setting the resolution at
-   boot time, allowing the use of a fixed-frequency monitor.
- * Complete code rewrite to follow Geert's skeletonfb spec which will allow
-   future implementation of hardware acceleration and other features.
+This version is an almost complete rewrite of the code written by Geert
+Uytterhoeven, which was based on the original TGA console code written by
+Jay Estabrook.
+
+Major new features since Linux 2.0.x:
+
+ * Support for multiple resolutions
+ * Support for fixed-frequency and other oddball monitors 
+   (by allowing the video mode to be set at boot time)
+
+User-visible changes since Linux 2.2.x:
+
+ * Sync-on-green is now handled properly
+ * More useful information is printed on bootup
+   (this helps if people run into problems)
+
+This driver does not (yet) support the TGA2 family of framebuffers, so the
+PowerStorm 3D30/4D20 (also known as PBXGB) cards are not supported. These
+can however be used with the standard VGA Text Console driver.
 
 
 Configuration
@@ -32,19 +42,27 @@
 
 font:X    - default font to use. All fonts are supported, including the
             SUN12x22 font which is very nice at high resolutions.
-mode:X    - default video mode. See drivers/video/tgafb.c for a list.
-            
-X11
-===
-
-XF68_FBDev should work just fine, but I haven't tested it.  Running
-the XF86_TGA server (reasonably recent versions of which support all TGA
-cards) works fine for me.
-
-One minor problem with XF86_TGA is when running tgafb in resolutions higher
-than 640x480, on switching VCs from tgafb to X, the entire screen is not
-re-drawn and must be manually refreshed. This is an X server problem, not a
-tgafb problem.
+
+mode:X    - default video mode. The following video modes are supported:
+            640x480-60, 800x600-56, 640x480-72, 800x600-60, 800x600-72, 
+	    1024x768-60, 1152x864-60, 1024x768-70, 1024x768-76,
+	    1152x864-70, 1280x1024-61, 1024x768-85, 1280x1024-70,
+	    1152x864-84, 1280x1024-76, 1280x1024-85
+ 
+
+Known Issues
+============
+
+The XFree86 FBDev server has been reported not to work, since tgafb doesn't do
+mmap(). Running the standard XF86_TGA server from XFree86 3.3.x works fine for
+me, however this server does not do acceleration, which make certain operations
+quite slow. Support for acceleration is being progressively integrated in
+XFree86 4.x.
+
+When running tgafb in resolutions higher than 640x480, on switching VCs from
+tgafb to XF86_TGA 3.3.x, the entire screen is not re-drawn and must be manually
+refreshed. This is an X server problem, not a tgafb problem, and is fixed in
+XFree86 4.0.
 
 Enjoy!
 
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.3.99-pre5/linux/Documentation/filesystems/devfs/ChangeLog	Tue Mar  7 14:32:25 2000
+++ linux/Documentation/filesystems/devfs/ChangeLog	Fri Apr 21 16:11:05 2000
@@ -1480,3 +1480,19 @@
   <devfs_readdir>
 
 - Only set auto-ownership for /dev/pty/s*
+===============================================================================
+Changes for patch v162
+
+Work sponsored by SGI
+
+- Set inode->i_size to correct size for symlinks
+  Thanks to Jeremy Fitzhardinge <jeremy@goop.org>
+
+- Only give lookup() method to directories to comply with new VFS
+  assumptions
+
+- Remove unnecessary tests in symlink methods
+
+- Don't kill existing block ops in <devfs_read_inode>
+
+- Restore auto-ownership for /dev/pty/m*
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/filesystems/devfs/modules.conf linux/Documentation/filesystems/devfs/modules.conf
--- v2.3.99-pre5/linux/Documentation/filesystems/devfs/modules.conf	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/filesystems/devfs/modules.conf	Fri Apr 21 16:11:05 2000
@@ -38,7 +38,7 @@
 
 # SCSI tapes
 probeall	/dev/st		scsi-hosts st
-alias		/dev/st*	/dev/sr
+alias		/dev/st*	/dev/st
 alias		/dev/nst*	/dev/st
 
 # SCSI generic
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/ia64/efirtc.txt linux/Documentation/ia64/efirtc.txt
--- v2.3.99-pre5/linux/Documentation/ia64/efirtc.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/ia64/efirtc.txt	Fri Apr 21 15:21:23 2000
@@ -0,0 +1,128 @@
+EFI Real Time Clock driver
+-------------------------------
+S. Eranian <eranian@hpl.hp.com>
+March 2000
+
+I/ Introduction
+
+This document describes the efirtc.c driver has provided for
+the IA-64 platform. 
+
+The purpose of this driver is to supply an API for kernel and user applications
+to get access to the Time Service offered by EFI version 0.92.
+
+EFI provides 4 calls one can make once the OS is booted: GetTime(),
+SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this driver.
+We describes those calls as well the the design of the driver in the following
+sections.
+
+II/ Design Decisions
+
+The original ideas was to provide a very simple  driver to get access to, 
+at first, the time of day service. This is required in order to access, in a 
+portable way, the CMOS clock. A program like /sbin/hwclock uses such a clock 
+to initialize the system view of the time during boot.
+
+Because we wanted to minimize the impact on existing user-level apps using
+the CMOS clock, we decided to expose an API that was very similar to the one
+used today with the legacy RTC driver (driver/char/rtc.c). However, because 
+EFI provides a simpler services, not all all ioctl() are available. Also
+new ioctl()s have been introduced for things that EFI provides but not the 
+legacy.
+
+EFI uses a slightly different way of representing the time, noticeably
+the reference date is different. Year is the using the full 4-digit format.
+The Epoch is January 1st 1998. For backward compatibility reasons we don't
+expose this new way of representing time. Instead we use something very 
+similar to the struct tm, i.e. struct rtc_time, as used by hwclock.
+One of the reasons for doing it this way is to allow for EFI to still evolve
+without necessarily impatcing any of the user applications. The decoupling
+enables flexibility and permits writing wrapper code is ncase things change.
+
+The driver exposes two interfaces, one via the device file and a set of ioctl()s.
+The other is read-only via the /proc filesystem. 
+
+As of today we don't offer a /proc/sys interface.
+
+To allow for a uniform interface between the legacy RTC and EFI time service,
+we have created the include/linux/rtc.h header file to contain only the 
+"public" API of the two drivers.  The specifics of the legacy RTC are still 
+in include/linux/mc146818rtc.h.
+
+ 
+III/ Time of day service
+
+The part of the driver gives access to the time of day service of EFI.
+Two ioctl()s, compatible with the legacy RTC calls:
+
+	Read the CMOS clock: ioctl(d, RTC_RD_TIME, &rtc);
+
+	Write the CMOS clock: ioctl(d, RTC_SET_TIME, &rtc);
+
+The rtc is a pointer to a data structure defined in rtc.h which is close
+to a struct tm:
+
+struct rtc_time {
+        int tm_sec;
+        int tm_min;
+        int tm_hour;
+        int tm_mday;
+        int tm_mon;
+        int tm_year;
+        int tm_wday;
+        int tm_yday;
+        int tm_isdst;
+};
+
+The driver takes care of converting back an forth between the EFI time and
+this format.
+
+Those two ioctl()s can be exercised with the hwclock command:
+
+For reading:
+# /sbin/hwclock --show
+Mon Mar  6 15:32:32 2000  -0.910248 seconds
+
+For setting:
+# /sbin/hwclock --systohc
+
+Root privileges are required to be able to set the time of day.
+
+IV/ Wakeup Alarm service
+
+EFI provides an API by which one can program when a machine should wakeup,
+i.e. reboot. This is very different from the alarm provided by the legacy
+RTC which is some kind of interval timer alarm. For this reason we don't use
+the same ioctl()s to get access to the service. Instead we have
+introduced 2 news ioctl()s to the interface of an RTC. 
+
+We have added 2 new ioctl()s that are specific to the EFI driver:
+
+	Read the current state of the alarm
+	ioctl(d, RTC_WKLAM_RD, &wkt)
+
+	Set the alarm or change its status
+	ioctl(d, RTC_WKALM_SET, &wkt)
+
+The wkt structure encapsulates a struct rtc_time + 2 extra fields to get 
+status information:
+	
+struct rtc_wkalrm {
+
+        unsigned char enabled; /* =1 if alarm is enabled */
+        unsigned char pending; /* =1 if alarm is pending  */
+
+        struct rtc_time time;
+} 
+
+As of today, none of the existing user-level apps supports this feature.
+However writing such a program should be hard by simply using those two 
+ioctl(). 
+
+Root privileges are required to be able to set the alarm.
+
+V/ References.
+
+Checkout the following Web site for more information on EFI:
+
+http://developer.intel.com/technology/efi/
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.3.99-pre5/linux/Documentation/ioctl-number.txt	Sat Feb 26 22:31:37 2000
+++ linux/Documentation/ioctl-number.txt	Thu Apr 13 09:00:51 2000
@@ -28,8 +28,9 @@
 I'll register one for you.
 
 The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
-to distinguish ioctls from each other.  The third argument is the size
-of the structure going into the kernel or coming out of the kernel.
+to distinguish ioctls from each other.  The third argument to _IOW,
+_IOR, or _IOWR is the type of the data going into the kernel or coming
+out of the kernel (e.g.  'int' or 'struct foo').
 
 Some devices use their major number as the identifier; this is OK, as
 long as it is unique.  Some devices are irregular and don't follow any
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/kernel-docs.txt linux/Documentation/kernel-docs.txt
--- v2.3.99-pre5/linux/Documentation/kernel-docs.txt	Fri Jan 21 18:19:15 2000
+++ linux/Documentation/kernel-docs.txt	Tue Apr 25 16:53:13 2000
@@ -164,6 +164,18 @@
        different situations. We also investigate the complex topic of
        DMA".
        
+     * Title: "Device Drivers Concluded"
+       Author: Georg v. Zezschwitz.
+       URL: http://www2.linuxjournal.com/lj-issues/issue28/1287.html
+       Keywords: address spaces, pages, pagination, page management,
+       demand loading, swapping, memory protection, memory mapping, mmap,
+       virtual memory areas (VMAs), vremap, PCI.
+       Description: Finally, the above turned out into a five articles
+       series. This latest one's introduction reads: "This is the last of
+       five articles about character device drivers. In this final
+       section, Georg deals with memory mapping devices, beginning with
+       an overall description of the Linux memory management concepts".
+       
      * Title: "Network Buffers And Memory Management"
        Author: Alan Cox.
        URL: http://www.ssc.com/lj/issue30/kk30.html
@@ -234,11 +246,26 @@
        Description: 68 pages paper on writing character drivers. A little
        bit old (1.993, 1.994) although still useful.
        
+     * Title: "Design and Implementation of the Second Extended
+       Filesystem"
+       Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
+       URL: http://web.mit.edu/tytso/www/linux/ext2intro.html
+       Keywords: ext2, linux fs history, inode, directory, link, devices,
+       VFS, physical structure, performance, benchmarks, ext2fs library,
+       ext2fs tools, e2fsck.
+       Description: Paper written by three of the top ext2 hackers.
+       Covers Linux filesystems history, ext2 motivation, ext2 features,
+       design, physical structure on disk, performance, benchmarks,
+       e2fsck's passes description... A must read!
+       Notes: This paper was first published in the Proceedings of the
+       First Dutch International Symposium on Linux, ISBN 90-367-0385-9.
+       
      * Title: "The Second Extended Filesystem"
        Author: Matthew Wilcox.
        URL: http://pocket.fluff.org/~mrw/linux/ext2.txt
        Keywords: ext2, filesystem.
-       Description: Description of ext2's blocks, directories, inodes ...
+       Description: Description of ext2's blocks, directories, inodes...
+       Notes: Seems to be DOWN. Anyone knows another link for it?
        
      * Title: "Analysis of the Ext2fs structure"
        Author: Louis-Dominique Dubeau.
@@ -247,6 +274,15 @@
        Description: Description of ext2's blocks, directories, inodes,
        bitmaps, invariants ...
        
+     * Title: "Journaling the Linux ext2fs Filesystem"
+       Author: Stephen C. Tweedie.
+       URL:
+       ftp://ftp.uk.linux.org:/pub/linux/sct/fs/jfs/journal-design.ps.gz
+       Keywords: ext3, journalist.
+       Description: Excellent 8-pages paper explaining the journaling
+       capabilities added to ext2 by the author, showing different
+       problems faced and the alternatives chosen.
+       
      * Title: "Kernel API changes from 2.0 to 2.2"
        Author: Richard Gooch.
        URL:
@@ -258,7 +294,7 @@
      * Title: "Kernel API changes from 2.2 to 2.3"
        Author: Richard Gooch.
        URL:
-       http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html
+       http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.3.html
        Keywords: 2.3, changes.
        Description: Kernel functions/structures/variables which changed
        from 2.2.x to 2.3.x.
@@ -295,6 +331,81 @@
        want a mechanism that is scalable. This means a large number of
        inactive FDs cost very little in memory and CPU time to manage".
        
+     * Title: "The Kernel Hacking HOWTO"
+       Author: Various Talented People, and Rusty.
+       URL: http://www.samba.org/~netfilter/kernel-hacking-HOWTO.html
+       Keywords: HOWTO, kernel contexts, deadlock, locking, modules,
+       symbols, return conventions.
+       Description: From the Introduction: "Please understand that I
+       never wanted to write this document, being grossly underqualified,
+       but I always wanted to read it, and this was the only way. I
+       simply explain some best practices, and give reading entry-points
+       into the kernel sources. I avoid implementation details: that's
+       what the code is for, and I ignore whole tracts of useful
+       routines. This document assumes familiarity with C, and an
+       understanding of what the kernel is, and how it is used. It was
+       originally written for the 2.3 kernels, but nearly all of it
+       applies to 2.2 too; 2.0 is slightly different. ".
+       
+     * Title: "ALSA 0.5.0 Developer documentation"
+       Author: Stephan 'Jumpy' Bartels .
+       URL: http://www.math.TU-Berlin.de/~sbartels/alsa/
+       Keywords: ALSA, sound, soundcard, driver, lowlevel, hardware.
+       Description: Advanced Linux Sound Architecture for developers,
+       both at kernel and user-level sides. Work in progress. ALSA is
+       supposed to be Linux's next generation sound architecture.
+       
+     * Title: "Programming Guide for Linux USB Device Drivers"
+       Author: Detlef Fliegl.
+       URL: http://usb.in.tum.de/usbdoc/
+       Keywords: USB, universal serial bus.
+       Description: A must-read. From the Preface: "This document should
+       give detailed information about the current state of the USB
+       subsystem and its API for USB device drivers. The first section
+       will deal with the basics of USB devices. You will learn about
+       different types of devices and their properties. Going into detail
+       you will see how USB devices communicate on the bus. The second
+       section gives an overview of the Linux USB subsystem [2] and the
+       device driver framework. Then the API and its data structures will
+       be explained step by step. The last section of this document
+       contains a reference of all API calls and their return codes".
+       Notes: Beware: the main page states: "This document may not be
+       published, printed or used in excerpts without explicit permission
+       of the author". Fortunately, it may still be read...
+       
+     * Title: "Tour Of the Linux Kernel Source"
+       Author: Vijo Cherian.
+       URL: http://www.geocities.com/vijoc/tolks/tolks.html
+       Keywords: .
+       Description: A classic of this page! Was lost for a while and is
+       back again. Thanks Vijo! TOLKS: the name says it all. A tour of
+       the sources, describing directories, files, variables, data
+       structures... It covers general stuff, device drivers,
+       filesystems, IPC and Networking Code.
+       
+     * Title: "Linux Kernel Mailing List Glossary"
+       Author: John Levon.
+       URL: http://www.movement.uklinux.net/glossary.html
+       Keywords: glossary, terms, linux-kernel.
+       Description: From the introduction: "This glossary is intended as
+       a brief description of some of the acronyms and terms you may hear
+       during discussion of the Linux kernel".
+       
+     * Title: "Linux Kernel Locking HOWTO"
+       Author: Various Talented People, and Rusty.
+       URL:
+       http://netfilter.kernelnotes.org/unreliable-guides/kernel-locking-
+       HOWTO.html
+       Keywords: locks, locking, spinlock, semaphore, atomic, race
+       condition, bottom halves, tasklets, softirqs.
+       Description: The title says it all: document describing the
+       locking system in the Linux Kernel either in uniprocessor or SMP
+       systems.
+       Notes: "It was originally written for the later (>2.3.47) 2.3
+       kernels, but most of it applies to 2.2 too; 2.0 is slightly
+       different". Freely redistributable under the conditions of the GNU
+       General Public License.
+       
      BOOKS: (Not on-line)
    
      * Title: "Linux Device Drivers"
@@ -366,15 +477,33 @@
      * Title: "Linux Core Kernel Commentary. Guide to Insider's Knowledge
        on the Core Kernel od the Linux Code"
        Author: Scott Maxwell.
-       Publisher: ???.
+       Publisher: Coriolis.
        Date: 1999.
        Pages: 592.
        ISBN: 1-57610-469-9
-       Notes: CD-ROM included.
+       Notes: CD-ROM included. Line by line commentary of the kernel
+       code.
+       
+     * Title: "Linux IP Stacks Commentary"
+       Author: Stephen Satchell and HBJ Clifford.
+       Publisher: Coriolis.
+       Date: 2000.
+       Pages: ???.
+       ISBN: 1-57610-470-2
+       Notes: Line by line source code commentary book.
+       
+     * Title: "Programming for the real world - POSIX.4"
+       Author: Bill O. Gallmeister.
+       Publisher: O'Reilly & Associates, Inc..
+       Date: 1995.
+       Pages: ???.
+       ISBN: I-56592-074-0
+       Notes: Though not being directly about Linux, Linux aims to be
+       POSIX. Good reference.
        
      MISCELLANEOUS:
    
-     * Name: Linux Source Driver.
+     * Name: "Linux Source Driver"
        URL: http://lsd.linux.cz
        Keywords: Browsing source code.
        Description: "Linux Source Driver (LSD) is an application, which
@@ -385,27 +514,27 @@
        and variables) and LSD can generate patches for you on the fly
        (files, directories or kernel)".
        
-     * Name: Cross-Referencing Linux.
+     * Name: "Cross-Referencing Linux"
        URL: http://lxr.linux.no/source/
        Keywords: Browsing source code.
        Description: Another web-based Linux kernel source code browser.
        Lots of cross references to variables and functions. You can see
        where they are defined and where they are used.
        
-     * Name: Linux Weekly News.
+     * Name: "Linux Weekly News"
        URL: http://lwn.net
        Keywords: latest kernel news.
        Description: The title says it all. There's a fixed kernel section
        summarizing developers' work, bug fixes, new features and versions
        produced during the week. Published every Thursday.
        
-     * Name: Kernel Traffic.
+     * Name: "Kernel Traffic"
        URL: http://kt.linuxcare.com
        Keywords: linux-kernel mailing list, weekly kernel news.
        Description: Weekly newsletter covering the most relevant
        discussions of the linux-kernel mailing list.
        
-     * Name: CuTTiNG.eDGe.LiNuX.
+     * Name: "CuTTiNG.eDGe.LiNuX"
        URL: http://edge.kernelnotes.org
        Keywords: changelist.
        Description: Site which provides the changelist for every kernel
@@ -413,7 +542,7 @@
        the patches and describes them. Pointers to the patches are there,
        too.
        
-     * Name: New linux-kernel Mailing List FAQ.
+     * Name: "New linux-kernel Mailing List FAQ"
        URL: Original site:
        http://www.altern.org/andrebalsa/doc/lkml-faq.html
        URL: U.S. mirror site:
@@ -433,6 +562,45 @@
        Description: Set of slides, presumably from a presentation on the
        Linux VFS layer. Covers version 2.1.x, with dentries and the
        dcache.
+       
+     * Name: "Gary's Enciclopedia - The Linux Kernel"
+       Author: Gary (I suppose...).
+       URL: http://members.aa.net/~swear/pedia/kernel.html
+       Keywords: links, not found here?.
+       Description: Gary's Enciclopedia exists to allow the rapid finding
+       of documentation and other information of interest to GNU/Linux
+       users. It has about 4000 links to external pages in 150 major
+       categories. This link is for kernel-specific links, documents,
+       sites... Look there if you could not find here whar you were
+       looking for.
+       
+     * Name: "The home page of Linux-MM"
+       Author: The Linux-MM team.
+       URL: http://www.linux.eu.org/Linux-MM/
+       Keywords: memory management, Linux-MM, mm patches, TODO, docs,
+       mailing list.
+       Description: Site devoted to Linux Memory Mangement development.
+       Memory related patches, HOWTOs, links, mm developers... Don't miss
+       it if you are interested in memory management development!
+       
+     * Name: "Kernel Newbies IRC Channel"
+       URL: http://www.surriel.com/kernelnewbies.shtml
+       Keywords: IRC, newbies, channel, asking doubts.
+       Description: #kernelnewbies on irc.openprojects.net. From the web
+       page: "#kernelnewbies is an IRC network dedicated to the 'newbie'
+       kernel hacker. The audience mostly consists of people who are
+       learning about the kernel, working on kernel projects or
+       professional kernel hackers that want to help less seasoned kernel
+       people. [...] #kernelnewbies is on the Open Projects IRC Network,
+       try irc.openprojects.net or irc.<country>.openprojects.net as your
+       server and then /join #kernelnewbies".
+       
+     * Name: "linux-kernel mailing list archives and search engines"
+       URL: http://www.uwsg.indiana.edu/hypermail/linux/kernel/index.html
+       URL: http://www.kernelnotes.org/lnxlists/linux-kernel/
+       Keywords: linux-kernel, archives, search.
+       Description: Some of the linux-kernel mailing list archivers. If
+       you have a better/another one, please let me know.
      _________________________________________________________________
    
-   Document last updated on Tue Nov 30 11:20:00 CET 1999
+   Document last updated on Mon Apr 17 18:07:07 CEST 2000
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/dmfe.txt linux/Documentation/networking/dmfe.txt
--- v2.3.99-pre5/linux/Documentation/networking/dmfe.txt	Tue Mar 14 19:10:38 2000
+++ linux/Documentation/networking/dmfe.txt	Mon Apr 24 13:39:33 2000
@@ -16,17 +16,13 @@
 
   A. Compiler command:
 
-     A-1: For normal single processor kernel
+     A-1: For normal single or multiple processor kernel
           "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall 
             -Wstrict-prototypes -O6 -c dmfe.c"
 
-     A-2: For single processor and enable kernel module version function
+     A-2: For single or multiple processor with kernel module version function
           "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux/net/inet 
             -Wall -Wstrict-prototypes -O6 -c dmfe.c"
-
-     A-3: For multiple processors(SMP) and enable the module version function
-          "gcc -D__SMP__ -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux
-           /net/inet -Wall -Wstrict-prototypes -O6 -c dmfe.c"
 
 
   B. The following steps teach you how to active DM9102 board:
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/fore200e.txt linux/Documentation/networking/fore200e.txt
--- v2.3.99-pre5/linux/Documentation/networking/fore200e.txt	Sat Feb 26 22:31:37 2000
+++ linux/Documentation/networking/fore200e.txt	Fri Apr 14 09:37:10 2000
@@ -1,6 +1,26 @@
 
-Fore PCA-200E/SBA-200E ATM NIC Firmware Copyright Notice
---------------------------------------------------------
+FORE Systems PCA-200E/SBA-200E ATM NIC driver
+---------------------------------------------
+
+This driver adds support for the FORE Systems 200E-series ATM adapters
+to the Linux operating system. It is based on the earlier PCA-200E driver
+written by Uwe Dannowski.
+
+The driver simultaneously supports PCA-200E and SBA-200E adapters on
+i386, alpha (untested), powerpc, sparc and sparc64 archs.
+
+The intent is to enable the use of different models of FORE adapters at the
+same time, by hosts that have several bus interfaces (such as PCI+SBUS,
+PCI+MCA or PCI+EISA).
+
+Only PCI and SBUS devices are currently supported by the driver, but support
+for other bus interfaces such as EISA should not be too hard to add (this may
+be more tricky for the MCA bus, though, as FORE made some MCA-specific
+modifications to the adapter's AALI interface).
+
+
+Firmware Copyright Notice
+-------------------------
 
 Please read the fore200e_firmware_copyright file present
 in the linux/drivers/atm directory for details and restrictions.
@@ -13,26 +33,22 @@
 uploaded to the ATM adapters at system boot time or at module loading time. 
 The supplied firmware images should work with all adapters.
 
-However, if you encounter problems (firmware doesn't start or the driver
-is unable to read PROM data), you may consider trying another firmware
+However, if you encounter problems (the firmware doesn't start or the driver
+is unable to read the PROM data), you may consider trying another firmware
 version. Alternative binary firmware images can be found somewhere on the
-ForeThough CD-ROM supplied with your adapter by FORE Systems.
+ForeThought CD-ROM supplied with your adapter by FORE Systems.
 
 You can also get the latest firmware images from FORE Systems at
 http://www.fore.com. Register TACTics Online and go to
 the 'software updates' pages. The firmware binaries are part of
-the various ForeThough software distributions.
+the various ForeThought software distributions.
 
 Notice that different versions of the PCA-200E firmware exist, depending
 on the endianess of the host architecture. The driver is shipped with
 both little and big endian PCA firmware images.
 
 Name and location of the new firmware images can be set at kernel
-configuration time.
-
-
-Driver Rebuilding
------------------
+configuration time:
 
 1. Copy the new firmware binary files (with .bin, .bin1 or .bin2 suffix)
    to some directory, such as linux/drivers/atm.
@@ -40,11 +56,7 @@
 2. Reconfigure your kernel to set the new firmware name and location.
    Expected pathnames are absolute or relative to the drivers/atm directory.
 
-3. Delete the files drivers/atm/fore200e_pca_fw.[co] and/or fore200e_sba_fw.[co]
-   to ensure that the new firmware will be used when rebuilding the kernel or
-   the module.
-
-4. Rebuild and re-install your kernel or your module.
+3. Rebuild and re-install your kernel or your module.
 
 
 Feedback
@@ -52,4 +64,3 @@
 
 Feedback is welcome. Please send success stories/bug reports/
 patches/improvement/comments/flames to <lizzi@cnam.fr>.
-
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt
--- v2.3.99-pre5/linux/Documentation/networking/tulip.txt	Mon Mar 27 08:08:20 2000
+++ linux/Documentation/networking/tulip.txt	Fri Apr 14 10:09:00 2000
@@ -142,6 +142,10 @@
 
 Version history
 ===============
+0.9.4.3 (April 14, 2000):
+* mod_timer fix (Hal Murray)
+* PNIC2 resusitation (Chris Smith)
+
 0.9.4.2 (March 21, 2000):
 * Fix 21041 CSR7, CSR13/14/15 handling
 * Merge some PCI ids from tulip 0.91x
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt
--- v2.3.99-pre5/linux/Documentation/networking/vortex.txt	Mon Jan 22 12:52:34 1996
+++ linux/Documentation/networking/vortex.txt	Mon Apr 24 15:17:06 2000
@@ -1,8 +1,46 @@
 This document describes the usage and errata of the 3Com "Vortex" device
 driver for Linux.
 
+The driver was written by Donald Becker <becker@cesdis.gsfc.nasa.gov>
+
+Don is no longer the prime maintener of this version of the driver. 
+Please report problems to one or more of:
+
+  Andrew Morton <andrewm@uow.edu.au>
+  Netdev mailing list <netdev@oss.sgi.com>
+
+
 This driver supports the following hardware:
-	3c590, 3c592, 3c595, 3c597
+
+   3c590 Vortex 10Mbps
+   3c592 EISA 10mbps Demon/Vortex
+   3c597 EISA Fast Demon/Vortex
+   3c595 Vortex 100baseTx
+   3c595 Vortex 100baseT4
+   3c595 Vortex 100base-MII
+   3Com Vortex
+   3c900 Boomerang 10baseT
+   3c900 Boomerang 10Mbps Combo
+   3c900 Cyclone 10Mbps TPO
+   3c900 Cyclone 10Mbps Combo
+   3c900 Cyclone 10Mbps TPC
+   3c900B-FL Cyclone 10base-FL
+   3c905 Boomerang 100baseTx
+   3c905 Boomerang 100baseT4
+   3c905B Cyclone 100baseTx
+   3c905B Cyclone 10/100/BNC
+   3c905B-FX Cyclone 100baseFx
+   3c905C Tornado
+   3c980 Cyclone
+   3cSOHO100-TX Hurricane
+   3c555 Laptop Hurricane
+   3c575 Boomerang CardBus
+   3CCFE575 Cyclone CardBus
+   3CCFE575CT Cyclone CardBus
+   3CCFE656 Cyclone CardBus
+   3CCFEM656 Cyclone CardBus
+   3c450 Cyclone/unknown
+   3Com Boomerang (unknown version)
 
 When loaded as a module the following variables may be set:
  name	 type	description
@@ -33,3 +71,46 @@
 	16	Bus-master enable bit (experimental use only!)
 
 Details of the device driver implementation are at the top of the source file.
+
+Additional documentation is available at Don Becker's Linux Drivers site:
+
+  http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html
+
+
+Additional resources
+--------------------
+
+Donald Becker's driver development site:
+
+     http://cesdis.gsfc.nasa.gov/linux/
+
+Don's vortex-diag program is useful for inspecting the NIC's state:
+
+     http://cesdis.gsfc.nasa.gov/linux/diag/vortex-diag.c
+
+Don's mii-diag program may be used for inspecting and manipulating the
+NIC's Media Independent Interface subsystem:
+
+     http://cesdis.gsfc.nasa.gov/linux/diag/#mii-diag
+
+3Com's documentation for many NICs, including the ones supported by
+this driver is available at 
+
+     http://support.3com.com/partners/developer/developer_form.html
+
+A detailed changelog for the modifications which were made for 2.3
+series kernel is available at
+
+     http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3
+
+
+
+Cisco interoperability note from Walter Wong <wcw+@CMU.EDU>:
+
+  On a side note, adding HAS_NWAY seems to share a problem with the
+  Cisco 6509 switch.  Specifically, you need to change the spanning
+  tree parameter for the port the machine is plugged into to 'portfast'
+  mode.  Otherwise, the negotiation fails.  This has been an issue
+  we've noticed for a while but haven't had the time to track down.
+
+
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/ALS linux/Documentation/sound/ALS
--- v2.3.99-pre5/linux/Documentation/sound/ALS	Tue Mar 14 19:10:38 2000
+++ linux/Documentation/sound/ALS	Tue Apr 11 19:13:15 2000
@@ -13,9 +13,12 @@
 sound configuration section of the kernel config:
   - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
   - FM synthesizer (YM3812/OPL-3) support 
-Since the ALS-007/100/200 is a PnP card, the sound driver probably should be
-compiled as a module, with the isapnptools used to wake up the sound card.
-Set the "I/O base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit -
+Since the ALS-007/100/200 are PnP cards, ISAPnP support should probably be
+compiled in.
+
+Alternatively, if you decide not to use kernel level ISAPnP, you can use the
+user mode isapnptools to wake up the sound card, as in 2.2.X. Set the "I/O 
+base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit -
 either 0, 1 or 3) to the values used in your particular installation (they
 should match the values used to configure the card using isapnp).  The
 ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA"
@@ -41,3 +44,4 @@
 30 March 1998
 
 Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200
+Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info.
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32
--- v2.3.99-pre5/linux/Documentation/sound/AWE32	Sun Nov  7 16:37:33 1999
+++ linux/Documentation/sound/AWE32	Tue Apr 11 19:13:15 2000
@@ -9,9 +9,10 @@
 2) If your card is NOT "Plug-n-Play" then go to 5th step now. In the other case
 proceed to step 3.
 
-3) You should obtain isapnptools. I looked through other PnP packages 
-for Linux, but all they are either in deep unstable beta/alpha releases or 
-they are much worse than isapnptools. In my case isapnptools were included in 
+3) You should compile in kernel ISAPnP support or you should obtain isapnptools.
+If you choose kernel level ISAPnP skip to step 5. I looked through other PnP 
+packages for Linux, but all they are either in deep unstable beta/alpha releases
+or they are much worse than isapnptools. In my case isapnptools were included in
 a Linux distribution (Red Hat 5.x). If you also already have them then go to 
 step 4.
 
@@ -67,11 +68,7 @@
 
 In "make (x,menu)config" select in "Sound":
 select "OSS sound modules" as <M> (module)
-
-In "Additional low level sound drivers":
-"Additional low level sound drivers", "AWE32 synth" as <M> (module).
-Select "Additional low level sound drivers" as [y] (or [*] (yes)) (If it is not
-available as [y], select it as <M> (module))
+select "AWE32 Synth" as <M> (module)
 
 Now recompile the kernel (make dep; make (b)zImage, b(z)lilo, etc...;
 make modules; make modules_install), update your boot loader (if required) and
@@ -87,9 +84,7 @@
 
 alias midi awe_wave
 post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk
-options sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
 
-(on io=0xaaa irq=b.... you should use your own settings)
 That will enable the Sound Blaster and AWE wave synthesis.
 
 To play midi files you should get one of these programs:
@@ -107,4 +102,4 @@
 			    Yaroslav Rosomakho (alons55@dialup.ptt.ru)
 				    http://www.yar.opennet.ru
 
-Last Updated: 3Jan99
+Last Updated: 10Apr2000
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/README.awe linux/Documentation/sound/README.awe
--- v2.3.99-pre5/linux/Documentation/sound/README.awe	Thu Apr 29 11:53:41 1999
+++ linux/Documentation/sound/README.awe	Tue Apr 11 19:13:15 2000
@@ -23,11 +23,10 @@
 
 * NOTE TO LINUX USERS
 
-To enable this driver on linux-2.[01].x kernels, you need turn on both 
-"lowlevel drivers support" and "AWE32 synth support" options in sound
-menu when configure your linux kernel and modules.  The precise
-installation procedure is described in the AWE64-Mini-HOWTO and
-linux-kernel/Documetation/sound/AWE32.
+To enable this driver on linux-2.[01].x kernels, you need turn on 
+"AWE32 synth" options in sound menu when configure your linux kernel
+and modules.  The precise installation procedure is described in the
+AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32.
 
 If you're using PnP cards, the card must be initialized before loading
 the sound driver.  There're several options to do this:
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/README.modules linux/Documentation/sound/README.modules
--- v2.3.99-pre5/linux/Documentation/sound/README.modules	Sun Nov  7 16:37:33 1999
+++ linux/Documentation/sound/README.modules	Tue Apr 11 19:13:15 2000
@@ -33,6 +33,12 @@
 options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
 options adlib_card io=0x388     # FM synthesizer
 
+ Alternatively, if you have compiled in kernel level ISAPnP support:
+
+alias char-major-14 sb
+post-install sb /sbin/modprobe "-k" "adlib_card"
+options adlib_card io=0x388
+
   The effect of this is that the sound driver and all necessary bits and
 pieces autoload on demand, assuming you use kerneld (a sound choice) and
 autoclean when not in use. Also, options for the device drivers are
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/Soundblaster linux/Documentation/sound/Soundblaster
--- v2.3.99-pre5/linux/Documentation/sound/Soundblaster	Wed Aug 19 14:38:12 1998
+++ linux/Documentation/sound/Soundblaster	Tue Apr 11 19:13:15 2000
@@ -13,12 +13,19 @@
 dma16   	16-bit DMA channel for SB16 and equivalent cards (5,6,7)
 mpu_io		I/O for MPU chip if present (0x300,0x330)
 
-mad16=1 	Set when loading this as part of the MAD16 setup only
-trix=1  	Set when loading this as part of the Audiotrix setup only
-pas2=1		Set when loading this as part of the Pas2 setup only
 sm_games=1	Set if you have a Logitech soundman games
 acer=1		Set this to detect cards in some ACER notebooks
 mwave_bug=1	Set if you are trying to use this driver with mwave (see on)
+type		Use this to specify a specific card type
+
+The following arguments are taken if ISAPnP support is compiled in
+
+isapnp=0	Set this to disable ISAPnP detection (use io=0xXXX etc. above)
+multiple=1	Set to enable detection of multiple Soundblaster cards.
+reverse=1	Reverses the order of the search in the PnP table.
+uart401=1	Set to enable detection of mpu devices on some clones.
+isapnpjump	Jumps to a specific slot in the driver's PnP table. Use the
+		source, Luke.
 
 You may well want to load the opl3 driver for synth music on most SB and
 clone SB devices
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sx.txt linux/Documentation/sx.txt
--- v2.3.99-pre5/linux/Documentation/sx.txt	Thu Aug  5 14:47:44 1999
+++ linux/Documentation/sx.txt	Mon Apr 24 13:39:33 2000
@@ -175,8 +175,13 @@
 		works). 
 
 	sx_irqmask: The mask of allowable IRQs to use. I suggest you set 
-                this to 0 (disable IRQs all together) and use polling if 
-		the assignment of IRQs becomes problematic.
+		this to 0 (disable IRQs all together) and use polling if 
+		the assignment of IRQs becomes problematic. This is defined
+		as the sum of (1 << irq) 's that you want to allow. So 
+		sx_irqmask of 8 (1 << 3) specifies that only irq 3 may
+		be used by the SX driver. If you want to specify to the 
+		driver: "Either irq 11 or 12 is ok for you to use", then
+		specify (1 << 11) | (1 << 12) = 0x1800 . 
 
 	sx_debug: You can enable different sorts of debug traces with this. 
 		At "-1" all debugging traces are active. You'll get several
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/usb/dc2xx.txt linux/Documentation/usb/dc2xx.txt
--- v2.3.99-pre5/linux/Documentation/usb/dc2xx.txt	Fri Jan 21 18:19:15 2000
+++ linux/Documentation/usb/dc2xx.txt	Fri Apr 21 14:03:00 2000
@@ -1,4 +1,4 @@
-19 January 2000
+14 April 2000
 david-b@pacbell.net
 
 This is an overview of how to use the "dc2xx" USB driver with certain
@@ -17,30 +17,22 @@
 
 In addition the DC-220, DC-260, DC-265, and DC-290 are also recognized.
 However, like other cameras using the "Digita OS" (from www.flashpoint.com)
-there is no gPhoto support for this camera.  At this writing the best
-known support for these cameras is a Python script that supports image
-downloading from those cameras.  (See archives of the linux-usb mailing
-list.)  When it becomes available, the HP PhotoSmart C500 should also
-work ... it's another Digita OS camera with USB support.
-
-It's likely that other digital still cameras can also use this USB driver,
-even if they're not from Kodak and don't use Digita.  The reason is that
-most currently known USB still camera protocols treat USB like a faster
-packet-carrying connection than a serial line, which is exactly how this
-driver looks to an application.
+there is no gPhoto support for this camera.  There is a python script
+for accessing these cameras (see archives of the linux-usb mailing list)
+and a "Digita Services" library that can also use this driver.
+
+The HP PhotoSmart C500 should also work, since it's another Digita camera
+with USB support.
 
 
 USB HARDWARE
 
-This has been shown to work on x86 OHCI and UHCI (Intel) chipsets.  OHCI has
-been trouble free; not so with UHCI, which was first seen to be happy with
-2.3.24 kernels, and has not been as fast as OHCI.  Users on the PowerMac
-platform have had success, although the stock kernel doesn't yet support
-that platform.
+Recent kernels have had no particular problems using this driver with
+either OHCI or UHCI chipsets, and have worked on the PowerMac platform.
 
 Note that in some cases changes in BIOS settings may be needed before
 your USB works.  At least one user has reported a need for SMP-related 
-settings as well.
+settings as well, and some old hardware may not handle USB correctly.
 
 
 SETUP
@@ -50,15 +42,18 @@
 
 Create at least one device, perhaps like this (both read and write):
 
-    # mknod -m 0666 /dev/kodak00 c 180 80
-    # mknod -m 0666 /dev/kodak01 c 180 81
+    # mknod -m 0660 /dev/usb/dc2xx0 c 180 80
+    # mknod -m 0660 /dev/usb/dc2xx1 c 180 81
     ...
 
+NOTE:  you would normally configure PAM so that the user logged in at
+the console is granted ownership of these devices.  console.perms(5)
+explains how to do this.
+
 The driver supports multiple device nodes.  The USB framework supports
-a maximum of sixteen device nodes (up to minor device number 96), though
-by default fewer devices are available.
+a maximum of sixteen device nodes (up to minor device number 96).
 
-When you plug in one camera, it will use the first device node (kodak00
+When you plug in one camera, it will use the first device node (dc2xx0
 in the example above).  A second camera will use the second device node,
 and so on.
 
@@ -69,18 +64,22 @@
 itself up correctly.
 
     - You should see an entry in /proc/bus/usb/drivers for "dc2xx",
-      if you enabled USB /proc support.
+      if you enabled USB /proc support and correctly mounted the
+      usbdevfs on /proc/bus/usb.
 
 Second:  when you connect your camera to the computer, does it get recognized
 by the driver?  (Make sure the camera is powered on!)
 
     - if you've got /proc/bus/usb/devices, you should see an entry
       something like this.  The "ProdID" may be different if you didn't
-      plug in a DC-240, but the "Driver=dc2xx" had better be there.
+      plug in a DC-240, as may the strings presented, but "Driver=dc2xx"
+      had better be there.
 
 	T:  Lev=01 Prnt=00 Port=00 Cnt=01 Dev#=  1 Spd=12  MxCh= 0
 	D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 	P:  Vendor=040a ProdID=0120 Rev= 1.08
+	S:  Manufacturer=Eastman Kodak Company
+	S:  Product=KODAK DC240 Zoom Digital Camera
 	C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
 	I:  If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
 	E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
@@ -90,13 +89,12 @@
 
 	Manufacturer: Eastman Kodak Company
 	Product: KODAK DC240 Zoom Digital Camera
-	Serial Number: ?
 	dc2xx.c: USB Camera #0 connected
 
 Third:  (optional) can you use gPhoto to talk to the camera?
 
-    - When you configure your camera, tell it to use "/dev/kodak00" (or
-      whatever name you used).  Right now, gPhoto emits a diagnostic
+    - When you configure your camera, tell it to use "/dev/usb/dc2xx0"
+      (or whatever name you used).  Right now, gPhoto emits a diagnostic
       message (non-GUI) saying that it since it didn't act like a TTY,
       it's assuming it's got a USB connection.
 
diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/video4linux/README.cpia linux/Documentation/video4linux/README.cpia
--- v2.3.99-pre5/linux/Documentation/video4linux/README.cpia	Tue Apr 11 15:09:11 2000
+++ linux/Documentation/video4linux/README.cpia	Thu Apr 13 09:25:44 2000
@@ -51,12 +51,12 @@
 CONFIG_VIDEO_CPIA=m
 CONFIG_VIDEO_CPIA_PP=m
 
-For autoloading of all those modules you need to tell kerneld some
-stuff. Add the following line to your kerneld config-file
+For autoloading of all those modules you need to tell modutils some
+stuff. Add the following line to your modutils config-file
 (e.g. /etc/modules.conf or wherever your distribution does store that
 stuff):
 
-options parport_pc dma=3 irq=7
+options parport_pc io=0x378 irq=7 dma=3
 alias char-major-81 cpia_pp
 
 The first line tells the dma/irq channels to use. Those _must_ match
diff -u --recursive --new-file v2.3.99-pre5/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.99-pre5/linux/MAINTAINERS	Tue Apr 11 15:09:11 2000
+++ linux/MAINTAINERS	Tue Apr 25 17:38:33 2000
@@ -50,7 +50,7 @@
 Maintainers List (try to look for most precise areas first)
 
 Note: For the hard of thinking, this list is meant to remain in alphabetical
-order. If you could add yourselves to it in alphabetical order that would
+order. If you could add yourselves to it in alphabetical order that would be
 so much easier [Ed]
 
 P: Person
@@ -147,7 +147,7 @@
 ARM PORT
 P:	Russell King
 M:	linux@arm.linux.org.uk
-L:	linux-arm@vger.rutgers.edu
+L:	linux-arm-kernel@lists.arm.linux.org.uk
 W:	http://www.arm.linux.org.uk/
 S:	Maintained
 
@@ -205,7 +205,7 @@
 COMPUTONE INTELLIPORT MULTIPORT CARD
 P:     Doug McNash
 P:     Michael H. Warfield
-M:     Doug McNash <dmcnash@computone.com>
+M:     Doug McNash <dougm@computone.com>
 M:     Michael H. Warfield <mhw@wittsend.com>
 W:     http://www.computone.com/
 W:     http://www.wittsend.com/computone.html
@@ -340,6 +340,13 @@
 M:	saw@saw.sw.com.sg
 S:	Maintained
 
+EMU10K1 SOUND DRIVER
+P:	Rui Sousa	
+M:	rsousa@grad.physics.sunysb.edu	
+L:	emu10k1-devel@opensource.creative.com
+W:	http://opensource.creative.com/
+S:	Maintained
+
 ETHEREXPRESS-16 NETWORK DRIVER
 P:	Philip Blundell
 M:	Philip.Blundell@pobox.com
@@ -474,9 +481,11 @@
 
 IDE DRIVER [GENERAL]
 P:	Andre Hedrick
+M:	andre@linux-ide.org
 M:	andre@suse.com
 L:	linux-kernel@vger.rutgers.edu
-W:	http://linux.kernel.org/pub/linux/kernel/people/hedrick/
+W:	http://www.kernel.org/pub/linux/kernel/people/hedrick/
+W:	http://www.linux-ide.org/
 S:	Supported
 
 IDE/ATAPI CDROM DRIVER
@@ -590,6 +599,12 @@
 W:	http://csua.berkeley.edu/~gam3/knfsd
 S:	Maintained
 
+LANMEDIA WAN CARD DRIVER
+P:      Andrew Stanley-Jones
+M:      asj@lanmedia.com
+W:      http://www.lanmedia.com/
+S:      Supported
+ 
 LAPB module
 P:	Henner Eisen
 M:	eis@baty.hanse.de
@@ -611,9 +626,8 @@
 
 MAESTRO PCI SOUND DRIVER
 P:	Zach Brown
-M:	zab@redhat.com
-W:	http://people.redhat.com/zab/maestro/
-S:	Supported
+M:	zab@zabbo.net
+S:	Odd Fixes
 
 M68K
 P:	Jes Sorensen
@@ -969,7 +983,7 @@
 P:	Jakub Jelinek
 M:	jj@sunsite.ms.mff.cuni.cz
 P:	Anton Blanchard
-M:	anton@progsoc.uts.edu.au
+M:	anton@linuxcare.com
 L:	sparclinux@vger.rutgers.edu
 L:	ultralinux@vger.rutgers.edu
 W:	http://ultra.linux.cz
diff -u --recursive --new-file v2.3.99-pre5/linux/Makefile linux/Makefile
--- v2.3.99-pre5/linux/Makefile	Wed Apr 12 10:02:34 2000
+++ linux/Makefile	Mon Apr 24 15:17:07 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 3
 SUBLEVEL = 99
-EXTRAVERSION = -pre5
+EXTRAVERSION = -pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -33,7 +33,6 @@
 STRIP		= $(CROSS_COMPILE)strip
 OBJCOPY		= $(CROSS_COMPILE)objcopy
 OBJDUMP		= $(CROSS_COMPILE)objdump
-MAKE		= make
 MAKEFILES	= $(TOPDIR)/.config
 GENKSYMS	= /sbin/genksyms
 MODFLAGS	= -DMODULE
@@ -342,6 +341,10 @@
 	if [ -f PCMCIA_SCSI_MODULES ]; then inst_mod PCMCIA_SCSI_MODULES pcmcia; fi; \
 	\
 	ls -1 -U *.o | sort > $$MODLIB/.allmods; \
+	if [ -f $$MODLIB/net/3c59x.o ]; then \
+		mkdir -p $$MODLIB/pcmcia; \
+		ln -nfs ../net/3c59x.o $$MODLIB/pcmcia/3c575_cb.o; \
+		MODULES="$$MODULES 3c575_cb.o"; fi; \
 	echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \
 	if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \
 	rm -f $$MODLIB/.misc $$MODLIB/.allmods; \
@@ -370,6 +373,7 @@
 	rm -f drivers/char/conmakehash
 	rm -f drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist
 	rm -f drivers/sound/bin2hex drivers/sound/hex2hex
+	rm -f drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2}
 	rm -f net/khttpd/make_times_h
 	rm -f net/khttpd/times.h
 	rm -f submenu*
@@ -388,6 +392,7 @@
 	rm -f drivers/sound/msndperm.c
 	rm -f drivers/sound/pndsperm.c
 	rm -f drivers/sound/pndspini.c
+	rm -f drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw
 	rm -f .version .config* config.in config.old
 	rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
 	rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
@@ -410,14 +415,15 @@
 	sync
 
 sgmldocs: 
+	chmod 755 $(TOPDIR)/scripts/docgen
+	chmod 755 $(TOPDIR)/scripts/gen-all-syms
+	chmod 755 $(TOPDIR)/scripts/kernel-doc
 	$(MAKE) -C $(TOPDIR)/Documentation/DocBook books
 
 psdocs: sgmldocs
-	$(MAKE) -C scripts docproc
 	$(MAKE) -C Documentation/DocBook ps
 
 pdfdocs: sgmldocs
-	$(MAKE) -C scripts docproc
 	$(MAKE) -C Documentation/DocBook pdf
  
 sums:
diff -u --recursive --new-file v2.3.99-pre5/linux/REPORTING-BUGS linux/REPORTING-BUGS
--- v2.3.99-pre5/linux/REPORTING-BUGS	Thu Apr 29 11:53:41 1999
+++ linux/REPORTING-BUGS	Wed Apr 12 09:16:31 2000
@@ -46,8 +46,10 @@
 [7.1.] Software (add the output of the ver_linux script here)
 [7.2.] Processor information (from /proc/cpuinfo):
 [7.3.] Module information (from /proc/modules):
-[7.4.] SCSI information (from /proc/scsi/scsi)
-[7.5.] Other information that might be relevant to the problem
+[7.4.] Loaded driver and hardware information (/proc/ioports, /proc/iomem)
+[7.5.] PCI information ('lspci -vvv' as root)
+[7.6.] SCSI information (from /proc/scsi/scsi)
+[7.7.] Other information that might be relevant to the problem
        (please look in /proc and include all information that you
        think to be relevant):
 [X.] Other notes, patches, fixes, workarounds:
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.3.99-pre5/linux/arch/alpha/kernel/alpha_ksyms.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Mon Apr 24 13:39:34 2000
@@ -174,7 +174,7 @@
  * SMP-specific symbols.
  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(synchronize_irq);
 EXPORT_SYMBOL(flush_tlb_all);
@@ -199,10 +199,10 @@
 EXPORT_SYMBOL(write_lock);
 EXPORT_SYMBOL(read_lock);
 #endif
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 EXPORT_SYMBOL(__local_bh_count);
 EXPORT_SYMBOL(__local_irq_count);
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 EXPORT_SYMBOL(rtc_lock);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.3.99-pre5/linux/arch/alpha/kernel/entry.S	Mon Mar 27 08:08:21 2000
+++ linux/arch/alpha/kernel/entry.S	Mon Apr 24 13:39:34 2000
@@ -4,6 +4,7 @@
  * kernel entry-points
  */
 
+#include <linux/config.h>
 #include <asm/system.h>
 
 #define SIGCHLD 20
@@ -706,7 +707,7 @@
 	br	restore_all
 .end entSys
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
         .globl  ret_from_smp_fork
 .align 3
 .ent ret_from_smp_fork
@@ -715,7 +716,7 @@
 	mov	$17,$16
 	jsr	$31,schedule_tail
 .end ret_from_smp_fork
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 .align 3
 .ent reschedule
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.3.99-pre5/linux/arch/alpha/kernel/head.S	Wed Dec 15 10:43:16 1999
+++ linux/arch/alpha/kernel/head.S	Mon Apr 24 13:39:34 2000
@@ -7,6 +7,7 @@
  * the kernel global pointer and jump to the kernel entry-point.
  */
 
+#include <linux/config.h>
 #include <asm/system.h>
 
 .globl swapper_pg_dir
@@ -30,7 +31,7 @@
 	call_pal PAL_halt
 	.end __start
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	.align 3
 	.globl	__smp_callin
 	.ent	__smp_callin
@@ -52,7 +53,7 @@
 	jsr	$26,smp_callin
 	call_pal PAL_halt
 	.end __smp_callin
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 	#
 	# The following two functions are needed for supporting SRM PALcode
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.3.99-pre5/linux/arch/alpha/kernel/irq.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/alpha/kernel/irq.c	Thu Apr 13 17:06:00 2000
@@ -373,7 +373,7 @@
 
 #ifdef CONFIG_SMP
 	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
 
 	entry->nlink = 1;
 	entry->data = (void *)(long)irq;
@@ -397,7 +397,7 @@
 
 #ifdef CONFIG_SMP
 	/* create /proc/irq/prof_cpu_mask */
-	entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
 
 	entry->nlink = 1;
 	entry->data = (void *)&prof_cpu_mask;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- v2.3.99-pre5/linux/arch/alpha/kernel/pci.c	Mon Mar 27 08:08:21 2000
+++ linux/arch/alpha/kernel/pci.c	Tue Apr 25 17:56:06 2000
@@ -110,10 +110,15 @@
 pcibios_align_resource(void *data, struct resource *res, unsigned long size)
 {
 	struct pci_dev *dev = data;
+	struct pci_controler *hose = dev->sysdata;
 	unsigned long alignto;
 	unsigned long start = res->start;
 
 	if (res->flags & IORESOURCE_IO) {
+		/* Make sure we start at our min on all hoses */
+		if (start - hose->io_space->start < PCIBIOS_MIN_IO)
+			start = PCIBIOS_MIN_IO + hose->io_space->start;
+
 		/*
 		 * Aligning to 0x800 rather than the minimum base of
 		 * 0x400 is an attempt to avoid having devices in 
@@ -121,11 +126,18 @@
 		 * probes for EISA cards.
 		 *
 		 * Adaptecs, especially, resent such intrusions.
+		 *
+		 * The de4x5 driver has the eisa probe conditionalized
+		 * out for Alpha, so lower the minimum base back to 0x400.
 		 */
-		alignto = MAX(0x800, size);
+		alignto = MAX(0x400, size);
 		start = ALIGN(start, alignto);
 	}
 	else if	(res->flags & IORESOURCE_MEM) {
+		/* Make sure we start at our min on all hoses */
+		if (start - hose->mem_space->start < PCIBIOS_MIN_MEM)
+			start = PCIBIOS_MIN_MEM + hose->io_space->start;
+
 		/*
 		 * The following holds at least for the Low Cost
 		 * Alpha implementation of the PCI interface:
@@ -230,7 +242,7 @@
 pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
 {
 	/* Update device resources.  */
-
+	struct pci_controler *hose = (struct pci_controler *)bus->sysdata;
 	int i;
 
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
@@ -238,10 +250,10 @@
 			continue;
 		if (dev->resource[i].flags & IORESOURCE_IO)
 			pcibios_fixup_resource(&dev->resource[i],
-					       bus->resource[0]);
+					       hose->io_space);
 		else if (dev->resource[i].flags & IORESOURCE_MEM)
 			pcibios_fixup_resource(&dev->resource[i],
-					       bus->resource[1]);
+					       hose->mem_space);
 	}
 	pcibios_assign_special(dev);
 }
@@ -257,6 +269,12 @@
 	bus->resource[0] = hose->io_space;
 	bus->resource[1] = hose->mem_space;
 
+	/* If this is a bridge, get the current bases */
+	if (bus->self) {
+		pci_read_bridge_bases(bus);
+		pcibios_fixup_device_resources(bus->self, bus->parent);
+	}
+
 	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
 		struct pci_dev *dev = pci_dev_b(ln);
 		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
@@ -268,10 +286,25 @@
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			struct resource *res, int resource)
 {
+	struct pci_controler *hose = dev->sysdata;
 	int where;
 	u32 reg;
 
+	if (resource < PCI_ROM_RESOURCE) 
 	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	else if (resource == PCI_ROM_RESOURCE)
+		where = dev->rom_base_reg;
+	else {
+	/* Don't update non-standard resources here */
+		return;
+	}
+
+	/* Point root at the hose root */
+	if (res->flags & IORESOURCE_IO)
+		root = hose->io_space;
+	if (res->flags & IORESOURCE_MEM)
+		root = hose->mem_space;
+
 	reg = (res->start - root->start) | (res->flags & 0xf);
 	pci_write_config_dword(dev, where, reg);
 	if ((res->flags & (PCI_BASE_ADDRESS_SPACE
@@ -319,10 +352,12 @@
 pcibios_fixup_pbus_ranges(struct pci_bus * bus,
 			  struct pbus_set_ranges_data * ranges)
 {
-	ranges->io_start -= bus->resource[0]->start;
-	ranges->io_end -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end -= bus->resource[1]->start;
+	struct pci_controler *hose = (struct pci_controler *)bus->sysdata;
+
+	ranges->io_start -= hose->io_space->start;
+	ranges->io_end -= hose->io_space->start;
+	ranges->mem_start -= hose->mem_space->start;
+	ranges->mem_end -= hose->mem_space->start;
 }
 
 int
@@ -332,6 +367,94 @@
 	return 0;
 }
 
+#define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+
+static void __init
+pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
+{
+	struct pbus_set_ranges_data inner;
+	struct pci_dev *dev;
+	struct pci_dev *bridge = bus->self;
+	struct pci_controler *hose = bus->sysdata;
+	struct list_head *ln;
+
+	if (!bridge)
+		return;	/* host bridge, nothing to do */
+
+	/* set reasonable default locations for pcibios_align_resource */
+	inner.io_start = hose->io_space->start + PCIBIOS_MIN_IO;
+	inner.mem_start = hose->mem_space->start + PCIBIOS_MIN_MEM;
+	inner.io_end = inner.io_start;
+	inner.mem_end = inner.mem_start;
+
+	/* Collect information about how our direct children are layed out. */
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		int i;
+		dev = pci_dev_b(ln);
+
+		/* Skip bridges for now */
+		if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
+			continue;
+
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource res;
+			unsigned long size;
+
+			memcpy(&res, &dev->resource[i], sizeof(res));
+			size = res.end - res.start + 1;
+
+			if (res.flags & IORESOURCE_IO) {
+				res.start = inner.io_end;
+				pcibios_align_resource(dev, &res, size);
+				inner.io_end = res.start + size;
+			} else if (res.flags & IORESOURCE_MEM) {
+				res.start = inner.mem_end;
+				pcibios_align_resource(dev, &res, size);
+				inner.mem_end = res.start + size;
+			}
+		}
+	}
+
+	/* And for all of the subordinate busses. */
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+		pcibios_size_bridge(pci_bus_b(ln), &inner);
+
+	/* turn the ending locations into sizes (subtract start) */
+	inner.io_end -= inner.io_start;
+	inner.mem_end -= inner.mem_start;
+
+	/* Align the sizes up by bridge rules */
+	inner.io_end = ROUND_UP(inner.io_end, 4*1024);
+	inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024);
+
+	/* Adjust the bridge's allocation requirements */
+	bridge->resource[0].end = bridge->resource[0].start + inner.io_end;
+	bridge->resource[1].end = bridge->resource[1].start + inner.mem_end;
+
+	/* adjust parent's resource requirements */
+	if (outer) {
+		outer->io_end = ROUND_UP(outer->io_end, 4*1024);
+		outer->io_end += inner.io_end;
+
+		outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024);
+		outer->mem_end += inner.mem_end;
+	}
+}
+
+#undef ROUND_UP
+
+static void __init 
+pcibios_size_bridges(void)
+{
+	struct list_head *ln1, *ln2;
+
+	for(ln1=pci_root_buses.next; ln1 != &pci_root_buses; ln1=ln1->next)
+		for(ln2 = pci_bus_b(ln1)->children.next; 
+		    ln2 != &pci_bus_b(ln1)->children;
+		    ln2 = ln2->next)
+			pcibios_size_bridge(pci_bus_b(ln2), NULL);
+}
+
 void __init
 common_init_pci(void)
 {
@@ -349,6 +472,7 @@
 		next_busno += 1;
 	}
 
+	pcibios_size_bridges();
 	pci_assign_unassigned_resources();
 	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
 	pci_set_bus_ranges();
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.3.99-pre5/linux/arch/alpha/kernel/process.c	Mon Mar 27 08:08:21 2000
+++ linux/arch/alpha/kernel/process.c	Mon Apr 24 13:39:34 2000
@@ -116,7 +116,7 @@
 	/* Clear reason to "default"; clear "bootstrap in progress". */
 	flags &= ~0x00ff0001UL;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Secondaries halt here. */
 	if (cpuid != boot_cpuid) {
 		flags |= 0x00040000UL; /* "remain halted" */
@@ -145,7 +145,7 @@
 	}
 	*pflags = flags;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Wait for the secondaries to halt. */
 	clear_bit(boot_cpuid, &cpu_present_mask);
 	while (cpu_present_mask)
@@ -184,7 +184,7 @@
 	struct halt_info args;
 	args.mode = mode;
 	args.restart_cmd = restart_cmd;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_call_function(common_shutdown_1, &args, 1, 0);
 #endif
 	common_shutdown_1(&args);
@@ -321,7 +321,7 @@
 	stack = ((struct switch_stack *) regs) - 1;
 	childstack = ((struct switch_stack *) childregs) - 1;
 	*childstack = *stack;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	childstack->r26 = (unsigned long) ret_from_smp_fork;
 #else
 	childstack->r26 = (unsigned long) ret_from_sys_call;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.3.99-pre5/linux/arch/alpha/kernel/proto.h	Sun Mar 19 18:35:30 2000
+++ linux/arch/alpha/kernel/proto.h	Mon Apr 24 13:39:34 2000
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 /* Prototypes of functions used across modules here in this directory.  */
 
 #define vucp	volatile unsigned char  *
@@ -132,7 +133,7 @@
 
 /* irq.c */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define mcheck_expected(cpu)	(cpu_data[cpu].mcheck_expected)
 #define mcheck_taken(cpu)	(cpu_data[cpu].mcheck_taken)
 #define mcheck_extra(cpu)	(cpu_data[cpu].mcheck_extra)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.3.99-pre5/linux/arch/alpha/kernel/setup.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/alpha/kernel/setup.c	Mon Apr 24 13:39:34 2000
@@ -484,7 +484,7 @@
 	 * Identify the flock of penguins.
 	 */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	setup_smp();
 #endif
 	paging_init();
@@ -930,7 +930,7 @@
 		       unaligned[1].count, unaligned[1].pc, unaligned[1].va,
 		       platform_string(), nr_processors);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	len += smp_info(buffer+len);
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.3.99-pre5/linux/arch/alpha/kernel/time.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/alpha/kernel/time.c	Mon Apr 24 13:39:34 2000
@@ -22,6 +22,7 @@
  *	fixed algorithm in do_gettimeofday() for calculating the precise time
  *	from processor cycle counter (now taking lost_ticks into account)
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -90,7 +91,7 @@
 	__u32 now;
 	long nticks;
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	/* Not SMP, do kernel PC profiling here.  */
 	if (!user_mode(regs))
 		alpha_do_profile(regs->pc);
@@ -315,7 +316,7 @@
 
 	read_unlock_irqrestore(&xtime_lock, flags);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Until and unless we figure out how to get cpu cycle counters
 	   in sync and keep them there, we can't use the rpcc tricks.  */
 	delta_usec = lost * (1000000 / HZ);
@@ -361,7 +362,7 @@
 	   must be subtracted out here to keep a coherent view of the
 	   time.  Without this, a full-tick error is possible.  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	delta_usec = lost_ticks * (1000000 / HZ);
 #else
 	delta_usec = rpcc() - state.last_time;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.3.99-pre5/linux/arch/alpha/kernel/traps.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/alpha/kernel/traps.c	Mon Apr 24 13:39:34 2000
@@ -95,7 +95,7 @@
 {
 	if (regs->ps & 8)
 		return;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	printk("CPU %d ", hard_smp_processor_id());
 #endif
 	printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.3.99-pre5/linux/arch/alpha/mm/fault.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/alpha/mm/fault.c	Mon Apr 24 15:49:21 2000
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -34,7 +35,7 @@
  * Force a new ASN for a task.
  */
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 unsigned long last_asn = ASN_FIRST_VERSION;
 #endif
 
@@ -139,7 +140,7 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	fault = handle_mm_fault(current, vma, address, cause > 0);
+	fault = handle_mm_fault(mm, vma, address, cause > 0);
 	up(&mm->mmap_sem);
 
 	if (fault < 0)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.3.99-pre5/linux/arch/alpha/mm/init.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/mm/init.c	Mon Apr 24 13:39:34 2000
@@ -37,7 +37,7 @@
 
 struct thread_struct original_pcb;
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 struct pgtable_cache_struct quicklists;
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S
--- v2.3.99-pre5/linux/arch/arm/boot/compressed/head.S	Fri Jan 21 18:19:15 2000
+++ linux/arch/arm/boot/compressed/head.S	Tue Apr 25 16:54:38 2000
@@ -6,6 +6,66 @@
 #include <linux/linkage.h>
 
 		.section ".start", #alloc, #execinstr
+
+/*
+ * Debugging stuff
+ */
+		.macro	kputc,val
+		mov	r0, \val
+		bl	putc
+		.endm
+
+		.macro	kphex,val,len
+		mov	r0, \val
+		mov	r1, #\len
+		bl	phex
+		.endm
+
+		.macro	debug_reloc_start
+#ifdef DEBUG
+		kputc	#'\n'
+		kphex	r6, 8
+		kputc	#':'
+		kphex	r5, 8
+		kputc	#'-'
+		kphex	r8, 8
+		kputc	#'>'
+		kphex	r4, 8
+		kputc	#'\n'
+#endif
+		.endm
+
+		.macro	debug_reloc_end
+#ifdef DEBUG
+		mov	r8, r0
+		kphex	r5, 8
+		kputc	#'-'
+		kphex	r8, 8
+		kputc	#'\n'
+		mov	r0, r4
+		bl	memdump
+#endif
+		.endm
+
+#if 0
+		.macro	loadsp,	rb
+		mov	\rb, #0x7c000000
+		.endm
+
+		.macro	writeb,	rb
+		strb	\rb, [r3, #0x3f8]
+		.endm
+#else
+		.macro	loadsp,	rb
+		mov	\rb, #0x03000000
+		orr	\rb, \rb, #0x00010000
+		.endm
+
+		.macro	writeb,	rb
+		strb	\rb, [r3, #0x3f8 << 2]
+		.endm
+#endif
+
 /*
  * sort out different calling conventions
  */
@@ -42,6 +102,8 @@
 		cmp	r2, r3
 		blt	1b
 
+		bl	cache_on
+
 		mov	r1, sp			@ malloc space above stack
 		add	r2, sp, #0x10000	@ 64k max
 
@@ -77,15 +139,87 @@
 		cmp	r2, r3
 		blt	1b
 
-		eor	r1, r6, #0x44 << 24	@ SA-110 or SA-1100?
-		eor	r1, r1, #0x01 << 16
-		eor	r1, r1, #0xa1 << 8
-		movs	r1, r1, lsr #5
-		mcreq	p15, 0, r1, c7, c7, 0	@ flush I & D-cache
-		mcreq	p15, 0, r1, c7, c10, 4	@ drain WB
+		bl	cache_clean_flush
 		add	pc, r5, r0		@ call relocation code
 
 /*
+ * Page table physical address list
+ */
+		.align	5
+		.type	pgtable,#object
+pgtable:	.word	0x00004000		@ 0x00
+		.word	0x10004000		@ 0x01
+		.word	0x00000000		@ 0x02
+		.word	0x40004000		@ 0x03
+		.word	0x00004000		@ 0x04
+		.word	0x00004000		@ 0x05
+		.word	0x00004000		@ 0x06
+		.word	0x80004000		@ 0x07
+		.word	0x00004000		@ 0x08
+		.word	0x00000000		@ 0x09
+		.word	0x00000000		@ 0x0a
+		.word	0x00000000		@ 0x0b
+		.word	0x00000000		@ 0x0c
+		.word	0x00000000		@ 0x0d
+		.word	0x10004000		@ 0x0e
+		.word	0x08004000		@ 0x0f
+		.word	0xc0004000		@ 0x10
+		.size	pgtable,. - pgtable
+1:
+
+		.type	LC0, #object
+LC0:		.word	__bss_start
+		.word	_end
+		.word	_load_addr
+		.word	_start
+		.word	user_stack+4096
+		.size	LC0, . - LC0
+
+		.align	5
+cache_on:	ldr	r1, proc_sa110_type
+		eor	r1, r1, r6
+		movs	r1, r1, lsr #5
+		movne	pc, lr
+		cmp	r7, #(1b - pgtable) >> 2
+		movge	pc, lr
+		adr	r3, pgtable
+		ldr	r3, [r3, r7, lsl #2]
+		teq	r3, #0
+		moveq	pc, lr
+/*
+ * Initialise the page tables
+ */
+		mov	r0, r3
+		mov	r8, r0, lsr #18
+		mov	r8, r8, lsl #18		@ start of RAM
+		add	r9, r8, #0x20000000	@ the maximum RAM size
+		mov	r1, #0x12
+		orr	r1, r1, #3 << 10
+		add	r2, r3, #16384
+1:		cmp	r1, r8			@ if virt > start of RAM
+		orrge	r1, r1, #0x0c		@ set cacheable, bufferable
+		cmp	r1, r9			@ if virt > end of RAM
+		bicge	r1, r1, #0x0c		@ clear cacheable, bufferable
+		str	r1, [r0], #4		@ 1:1 mapping
+		add	r1, r1, #1048576
+		teq	r0, r2
+		bne	1b
+
+		mov	r0, #0
+		mcr	p15, 0, r0, c7, c10, 4	@ drain write buffer
+		mcr	p15, 0, r0, c8, c7	@ flush I,D TLBs
+		mcr	p15, 0, r3, c2, c0	@ load page table pointer
+		mov	r0, #-1
+		mcr	p15, 0, r0, c3, c0	@ load domain access register
+		mrc	p15, 0, r0, c1, c0
+		orr	r0, r0, #0x1000		@ I-cache enable
+#ifndef DEBUG
+		orr	r0, r0, #0x003d		@ Write buffer, mmu
+#endif
+		mcr	p15, 0, r0, c1, c0
+		mov	pc, lr
+
+/*
  * r0     = decompressed kernel length
  * r1-r3  = unused
  * r4     = kernel execution address
@@ -94,87 +228,68 @@
  * r7     = architecture ID
  * r8-r14 = unused
  */
+		.align	5
 reloc_start:	add	r8, r5, r0
-#if 0
-	mov r0, #'\n'
-	bl putc
-	mov r0, r6
-	mov r1, #8
-	bl phex
-	mov r0, #':'
-	bl putc
-	mov r0, r5
-	mov r1, #8
-	bl phex
-	mov r0, #'-'
-	bl putc
-	mov r0, r8
-	mov r1, #8
-	bl phex
-	mov r0, #'>'
-	bl putc
-	mov r0, r4
-	mov r1, #8
-	bl phex
-	mov r0, #'\n'
-	bl putc
-#endif
-		mov	r0, r8
+		debug_reloc_start
 		mov	r1, r4
 1:
 		.rept	4
-		ldmia	r5!, {r2, r3, r8 - r13}	@ relocate kernel
-		stmia	r1!, {r2, r3, r8 - r13}
+		ldmia	r5!, {r0, r2, r3, r9 - r13}	@ relocate kernel
+		stmia	r1!, {r0, r2, r3, r9 - r13}
 		.endr
 
-		cmp	r5, r0
+		cmp	r5, r8
 		blt	1b
-#if 0
-	mov r8, r0
-	mov r0, r5
-	mov r1, #8
-	bl phex
-	mov r0, #'-'
-	bl putc
-	mov r0, r8
-	mov r1, #8
-	bl phex
-	mov r0, #'\n'
-	bl putc
-	mov r0, r4
-	bl  memdump
-#endif
-		eor	r0, r6, #0x44 << 24	@ SA-110 or SA-1100?
-		eor	r0, r0, #0x01 << 16
-		eor	r0, r0, #0xa1 << 8
-		movs	r0, r0, lsr #5
-		mcreq	p15, 0, r0, c7, c7, 0	@ flush I cache
-		mcreq	p15, 0, r1, c7, c10, 4	@ drain WB
+		debug_reloc_end
 
-call_kernel:	mov	r0, #0
+call_kernel:	bl	cache_clean_flush
+		bl	cache_off
+		mov	r0, #0
 		mov	r1, r7			@ restore architecture number
 		mov	pc, r4			@ call kernel
 
-phexbuf:	.space	12
+		.type	proc_sa110_type,#object
+proc_sa110_type:
+		.word	0x4401a100
+		.size	proc_sa110_type, . - proc_sa110_type
 
-#if 0
-		.macro	loadsp,	rb
-		mov	\rb, #0x7c000000
-		.endm
+/*
+ * Turn off StrongARM cache and MMU
+ */
+		.align	5
+cache_off:	ldr	r1, proc_sa110_type
+		eor	r1, r1, r6
+		movs	r1, r1, lsr #5
+		movne	pc, lr
+		mrc	p15, 0, r0, c1, c0
+		bic	r0, r0, #0x000d
+		mcr	p15, 0, r0, c1, c0
+		mov	pc, lr		
 
-		.macro	writeb,	rb
-		strb	\rb, [r3, #0x3f8]
-		.endm
-#else
-		.macro	loadsp,	rb
-		mov	\rb, #0x03000000
-		orr	\rb, \rb, #0x00010000
-		.endm
+/*
+ * Clean and flush the cache to maintain consistency.
+ */
+		.align	5
+cache_clean_flush:
+		ldr	r1, proc_sa110_type	@ SA-110 or SA-1100?
+		eor	r1, r1, r6
+		movs	r1, r1, lsr #5
+		movne	pc, lr
 
-		.macro	writeb,	rb
-		strb	\rb, [r3, #0x3f8 << 2]
-		.endm
-#endif
+		bic	r1, pc, #31
+		add	r2, r1, #32768
+1:		ldr	r12, [r1], #32
+		teq	r1, r2
+		bne	1b
+
+		mcr	p15, 0, r1, c7, c7, 0	@ flush I cache
+		mcr	p15, 0, r1, c7, c10, 4	@ drain WB
+		mov	pc, lr
+
+#ifdef DEBUG
+		.type	phexbuf,#object
+phexbuf:	.space	12
+		.size	phexbuf, . - phexbuf
 
 phex:		adr	r3, phexbuf
 		mov	r2, #0
@@ -240,14 +355,10 @@
 		cmp	r11, #64
 		blt	2b
 		mov	pc, r10
+#endif
+
 reloc_end:
 
-LC0:		.word	__bss_start
-		.word	_end
-		.word	_load_addr
-		.word	_start
-		.word	user_stack+4096
 		.align
-
 		.section	".stack"
 user_stack:	.space	4096
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.3.99-pre5/linux/arch/arm/config.in	Tue Apr 11 15:09:11 2000
+++ linux/arch/arm/config.in	Tue Apr 25 16:54:38 2000
@@ -137,9 +137,6 @@
    define_bool CONFIG_ISA_DMA n
 fi
 
-define_bool CONFIG_SBUS n
-define_bool CONFIG_PCMCIA n
-
 if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
    bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP
 fi
@@ -221,7 +218,6 @@
       fi
    fi
 fi
-
 
 #source drivers/misc/Config.in
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/def-configs/ebsa110 linux/arch/arm/def-configs/ebsa110
--- v2.3.99-pre5/linux/arch/arm/def-configs/ebsa110	Mon Jul 19 09:52:57 1999
+++ linux/arch/arm/def-configs/ebsa110	Tue Apr 25 16:54:38 2000
@@ -2,6 +2,12 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
 
 #
 # System and processor type
@@ -12,20 +18,13 @@
 CONFIG_ARCH_EBSA110=y
 # CONFIG_FOOTBRIDGE is not set
 # CONFIG_ARCH_ACORN is not set
-# CONFIG_ISA_DMA is not set
 CONFIG_CPU_32=y
 # CONFIG_CPU_26 is not set
-# CONFIG_CPU_ARM2 is not set
-# CONFIG_CPU_ARM3 is not set
-# CONFIG_CPU_ARM6 is not set
-# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_32v4=y
 CONFIG_CPU_SA110=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_TEXT_SECTIONS is not set
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
 
 #
 # Loadable module support
@@ -42,29 +41,52 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_NWFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=m
+CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Parallel port support
+#
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_PC_SUPERIO=y
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
 CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8"
 CONFIG_LEDS=y
 
 #
-# Plug and Play support
+# I2O device support
 #
-# CONFIG_PNP is not set
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
 
 #
-# Block devices
+# Plug and Play configuration
 #
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_IDE is not set
+# 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_HD_ONLY is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
 
 #
 # Additional Block Devices
@@ -74,10 +96,6 @@
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
 # Character devices
@@ -94,29 +112,39 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_PRINTER=m
-CONFIG_PRINTER_READBACK=y
-CONFIG_MOUSE=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
 
 #
 # Mice
 #
-# CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
+CONFIG_MOUSE=y
 # CONFIG_PSMOUSE is not set
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
 # CONFIG_QIC02_TAPE is not set
-CONFIG_WATCHDOG=y
 
 #
 # Watchdog Cards
 #
+CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 # CONFIG_WDT is not set
 CONFIG_SOFT_WATCHDOG=y
 # CONFIG_PCWATCHDOG is not set
 # CONFIG_ACQUIRE_WDT is not set
+# CONFIG_MIXCOMWD is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 
@@ -124,64 +152,92 @@
 # Video For Linux
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Joystick support
-#
-# CONFIG_JOYSTICK is not set
 # CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
 
 #
 # Networking options
 #
 CONFIG_PACKET=m
-# CONFIG_NETLINK is not set
-CONFIG_FIREWALL=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_TOS is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_ROUTE_LARGE_TABLES is not set
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
-CONFIG_IP_FIREWALL=y
-CONFIG_IP_ALWAYS_DEFRAG=y
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-CONFIG_IP_MASQUERADE=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-CONFIG_IP_MASQUERADE_ICMP=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_MOD is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
 
 #
 # (it is safe to leave these untouched)
 #
-# CONFIG_INET_RARP is not set
 # CONFIG_SKB_LARGE is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_FTP=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_LIMIT=y
+# CONFIG_IP_NF_MATCH_MAC is not set
+CONFIG_IP_NF_MATCH_MARK=y
+CONFIG_IP_NF_MATCH_MULTIPORT=y
+CONFIG_IP_NF_MATCH_TOS=y
+CONFIG_IP_NF_MATCH_STATE=y
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=y
+CONFIG_IP_NF_TARGET_MARK=y
+CONFIG_IP_NF_TARGET_LOG=y
 # CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
 
 #
 #  
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
@@ -190,7 +246,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
@@ -203,7 +258,7 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA subsystem support
+# IrDA (infrared) support
 #
 # CONFIG_IRDA is not set
 
@@ -211,37 +266,72 @@
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
 # CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
 CONFIG_NET_ETHERNET=y
 CONFIG_ARM_AM79C961A=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_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
 # CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA is not set
+# CONFIG_NET_PCI is not set
 # CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_DLCI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_SLIP is not set
 
 #
-# CCP compressors for PPP are only built as modules.
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
 # CONFIG_TR is not set
-# CONFIG_SHAPER is not set
-# CONFIG_HOSTESS_SV11 is not set
-# CONFIG_COSA is not set
+# CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
 
 #
 # SCSI support
@@ -249,27 +339,35 @@
 # CONFIG_SCSI is not set
 
 #
-# Filesystems
+# File systems
 #
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=y
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_EXT2_FS is not set
 # CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
 
 #
@@ -287,22 +385,28 @@
 #
 # Partition Types
 #
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
 # CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
 # CONFIG_MSDOS_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ACORN_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
+# USB support
+#
+# CONFIG_USB is not set
+
+#
 # Kernel hacking
 #
-CONFIG_FRAME_POINTER=y
+# CONFIG_FRAME_POINTER is not set
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_ARTHUR is not set
 # CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/defconfig linux/arch/arm/defconfig
--- v2.3.99-pre5/linux/arch/arm/defconfig	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/defconfig	Thu Apr 13 22:54:26 2000
@@ -536,8 +536,8 @@
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c
--- v2.3.99-pre5/linux/arch/arm/kernel/arch.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/kernel/arch.c	Tue Apr 25 16:54:38 2000
@@ -1,45 +1,39 @@
 /*
  * linux/arch/arm/kernel/arch.c
  *
- * Architecture specifics
+ * Architecture specific fixups.  This is where any
+ * parameters in the params struct are fixed up, or
+ * any additional architecture specific information
+ * is pulled from the params struct.
  */
 #include <linux/config.h>
 #include <linux/tty.h>
 #include <linux/init.h>
 
+#include <asm/dec21285.h>
 #include <asm/elf.h>
 #include <asm/setup.h>
 #include <asm/system.h>
 
 #include "arch.h"
 
-extern unsigned int system_rev;
-extern unsigned int system_serial_low;
-extern unsigned int system_serial_high;
-
 unsigned int vram_size;
-#ifdef CONFIG_ARCH_ACORN
-unsigned int memc_ctrl_reg;
-unsigned int number_mfm_drives;
-#endif
 
 extern void setup_initrd(unsigned int start, unsigned int size);
 extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
 
-/*
- * Architecture specific fixups.  This is where any
- * parameters in the params struct are fixed up, or
- * any additional architecture specific information
- * is pulled from the params struct.
- */
+#ifdef CONFIG_ARCH_ACORN
+
+unsigned int memc_ctrl_reg;
+unsigned int number_mfm_drives;
+
 static void __init
 fixup_acorn(struct machine_desc *desc, struct param_struct *params,
 	    char **cmdline, struct meminfo *mi)
 {
-#ifdef CONFIG_ARCH_ACORN
-	int i;
-
 	if (machine_is_riscpc()) {
+		int i;
+
 		/*
 		 * RiscPC can't handle half-word loads and stores
 		 */
@@ -69,9 +63,36 @@
 	}
 	memc_ctrl_reg	  = params->u1.s.memc_control_reg;
 	number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
-#endif
 }
 
+#ifdef CONFIG_ARCH_RPC
+MACHINE_START(RISCPC, "Acorn-RiscPC")
+	MAINTAINER("Russell King")
+	BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
+	BOOT_PARAMS(0x10000100)
+	DISABLE_PARPORT(0)
+	DISABLE_PARPORT(1)
+	FIXUP(fixup_acorn)
+MACHINE_END
+#endif
+#ifdef CONFIG_ARCH_ARC
+MACHINE_START(ARCHIMEDES, "Acorn-Archimedes")
+	MAINTAINER("Dave Gilbert")
+	BOOT_PARAMS(0x0207c000)
+	FIXUP(fixup_acorn)
+MACHINE_END
+#endif
+#ifdef CONFIG_ARCH_A5K
+MACHINE_START(A5K, "Acorn-A5000")
+	MAINTAINER("Russell King")
+	BOOT_PARAMS(0x0207c000)
+	FIXUP(fixup_acorn)
+MACHINE_END
+#endif
+#endif
+
+#ifdef CONFIG_ARCH_EBSA285
+
 static void __init
 fixup_ebsa285(struct machine_desc *desc, struct param_struct *params,
 	      char **cmdline, struct meminfo *mi)
@@ -82,6 +103,16 @@
 	ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
 }
 
+MACHINE_START(EBSA285, "EBSA285")
+	MAINTAINER("Russell King")
+	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+	BOOT_PARAMS(0x00000100)
+	VIDEO(0x000a0000, 0x000bffff)
+	FIXUP(fixup_ebsa285)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_NETWINDER
 /*
  * Older NeTTroms either do not provide a parameters
  * page, or they don't supply correct information in
@@ -105,6 +136,18 @@
 	}
 }
 
+MACHINE_START(NETWINDER, "Rebel-NetWinder")
+	MAINTAINER("Russell King/Rebel.com")
+	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+	BOOT_PARAMS(0x00000100)
+	VIDEO(0x000a0000, 0x000bffff)
+	DISABLE_PARPORT(0)
+	DISABLE_PARPORT(2)
+	FIXUP(fixup_netwinder)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_CATS
 /*
  * CATS uses soft-reboot by default, since
  * hard reboots fail on early boards.
@@ -118,11 +161,20 @@
 	ORIG_Y = 24;
 }
 
+MACHINE_START(CATS, "Chalice-CATS")
+	MAINTAINER("Philip Blundell")
+	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+	SOFT_REBOOT
+	FIXUP(fixup_cats)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_CO285
+
 static void __init
 fixup_coebsa285(struct machine_desc *desc, struct param_struct *params,
 		char **cmdline, struct meminfo *mi)
 {
-#if 0
 	extern unsigned long boot_memory_end;
 	extern char boot_command_line[];
 
@@ -131,242 +183,228 @@
 	mi->bank[0].size  = boot_memory_end;
 
 	*cmdline = boot_command_line;
-#endif
 }
 
+MACHINE_START(CO285, "co-EBSA285")
+	MAINTAINER("Mark van Doesburg")
+	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000)
+	FIXUP(fixup_coebsa285)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_SA1100
+
+extern void select_sa1100_io_desc(void);
+#define SET_BANK(__nr,__start,__size) \
+	mi->bank[__nr].start = (__start), \
+	mi->bank[__nr].size = (__size)
 static void __init
 fixup_sa1100(struct machine_desc *desc, struct param_struct *params,
 	     char **cmdline, struct meminfo *mi)
 {
-#ifdef CONFIG_ARCH_SA1100
-	int i;
-	extern struct mem_desc {
-		unsigned long phys_start;
-		unsigned long length;
-	} mem_desc[];
-	extern unsigned int mem_desc_size;
-
-	for( i = 0; i < mem_desc_size; i++ ) {
-		if( i >= NR_BANKS ) {
-			printk( __FUNCTION__ 
-				": mem_desc too large for meminfo structure\n");
-			break;
-		}
-		mi->bank[i].start = mem_desc[i].phys_start;
-		mi->bank[i].size = mem_desc[i].length;
+	select_sa1100_io_desc();
+
+	if (machine_is_assabet()) {
+		SET_BANK( 0, 0xc0000000, 32*1024*1024 );
+		mi->nr_banks = 1;
+
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+		setup_ramdisk( 1, 0, 0, 8192 );
+		setup_initrd( 0xc0800000, 3*1024*1024 );
+	}
+
+	else if (machine_is_brutus()) {
+		SET_BANK( 0, 0xc0000000, 4*1024*1024 );
+		SET_BANK( 1, 0xc8000000, 4*1024*1024 );
+		SET_BANK( 2, 0xd0000000, 4*1024*1024 );
+		SET_BANK( 3, 0xd8000000, 4*1024*1024 );
+		mi->nr_banks = 4;
+
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+		setup_ramdisk( 1, 0, 0, 8192 );
+		setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 );
+	}
+
+	else if (machine_is_empeg()) {
+		SET_BANK( 0, 0xc0000000, 4*1024*1024 );
+		SET_BANK( 1, 0xc8000000, 4*1024*1024 );
+		mi->nr_banks = 2;
+
+		ROOT_DEV = MKDEV( 3, 1 );  /* /dev/hda1 */
+		setup_ramdisk( 1, 0, 0, 4096 );
+		setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) );
+	}
+
+	else if (machine_is_lart()) {
+		/*
+		 * Note that LART is a special case - it doesn't use physical
+		 * address line A23 on the DRAM, so we effectively have 4 * 8MB
+		 * in two SA1100 banks.
+		 */
+		SET_BANK( 0, 0xc0000000, 8*1024*1024 );
+		SET_BANK( 1, 0xc1000000, 8*1024*1024 );
+		SET_BANK( 2, 0xc8000000, 8*1024*1024 );
+		SET_BANK( 3, 0xc9000000, 8*1024*1024 );
+		mi->nr_banks = 4;
+
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+		setup_ramdisk(1, 0, 0, 8192);
+		setup_initrd(0xc0400000, 4*1024*1024);
+	}
+
+	else if (machine_is_thinclient()) {
+		SET_BANK( 0, 0xc0000000, 16*1024*1024 );
+		mi->nr_banks = 1;
+
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+		setup_ramdisk( 1, 0, 0, 8192 );
+		setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
+	}
+
+	else if (machine_is_tifon()) {
+		SET_BANK( 0, 0xc0000000, 16*1024*1024 );
+		SET_BANK( 1, 0xc8000000, 16*1024*1024 );
+		mi->nr_banks = 2;
+
+		ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0);
+		setup_ramdisk(1, 0, 0, 4096);
+		setup_initrd( 0xd0000000 + 0x1100004, 0x140000 );
+	}
+
+	else if (machine_is_victor()) {
+		SET_BANK( 0, 0xc0000000, 4*1024*1024 );
+		mi->nr_banks = 1;
+
+		ROOT_DEV = MKDEV( 60, 2 );
+
+		/* Get command line parameters passed from the loader (if any) */
+		if( *((char*)0xc0000000) )
+			strcpy( *cmdline, ((char *)0xc0000000) );
+
+		/* power off if any problem */
+		strcat( *cmdline, " panic=1" );
 	}
-	mi->nr_banks = i;
 
-#if defined(CONFIG_SA1100_BRUTUS)
-	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
-	setup_ramdisk( 1, 0, 0, 8192 );
-	setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 );
-#elif defined(CONFIG_SA1100_EMPEG)
-	ROOT_DEV = MKDEV( 3, 1 );  /* /dev/hda1 */
-	setup_ramdisk( 1, 0, 0, 4096 );
-	setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) );
-#elif defined(CONFIG_SA1100_THINCLIENT)
-	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
-	setup_ramdisk( 1, 0, 0, 8192 );
-	setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
-#elif defined(CONFIG_SA1100_TIFON)
-	ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0);
-	setup_ramdisk(1, 0, 0, 4096);
-	setup_initrd( 0xd0000000 + 0x1100004, 0x140000 );
-#elif defined(CONFIG_SA1100_VICTOR)
-	ROOT_DEV = MKDEV( 60, 2 );
-
-	/* Get command line parameters passed from the loader (if any) */
-	if( *((char*)0xc0000000) )
-		strcpy( default_command_line, ((char *)0xc0000000) );
-
-	/* power off if any problem */
-	strcat( default_command_line, " panic=1" );
-#elif defined(CONFIG_SA1100_LART)
-	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
-	setup_ramdisk(1, 0, 0, 8192);
-	setup_initrd(0xc0400000, 0x00400000);
-#endif
-#endif
 }
 
-#define NO_PARAMS	0
-#define NO_VIDEO	0, 0
+#ifdef CONFIG_SA1100_ASSABET
+MACHINE_START(ASSABET, "Intel-Assabet")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_BITSY
+MACHINE_START(BITSY, "Compaq Bitsy")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_BRUTUS
+MACHINE_START(BRUTUS, "Intel Brutus (SA1100 eval board)")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_EMPEG
+MACHINE_START(EMPEG, "empeg MP3 Car Audio Player")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_ITSY
+MACHINE_START(ITSY, "Compaq Itsy")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_LART
+MACHINE_START(LART, "LART")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_PLEB
+MACHINE_START(PLEB, "PLEB")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_THINCLIENT
+MACHINE_START(THINCLIENT, "ADS ThinClient")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_TIFON
+MACHINE_START(TIFON, "Tifon")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_VICTOR
+MACHINE_START(VICTOR, "VisuAide Victor")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
+#endif
 
-/*
- * This is the list of all architectures supported by
- * this kernel.  This should be integrated with the list
- * in head-armv.S.
- */
-static struct machine_desc machine_desc[] __attribute__ ((__section__ (".arch.info"))) = {
 #ifdef CONFIG_ARCH_EBSA110
-	{
-		MACH_TYPE_EBSA110,
-		"EBSA110",	/* RMK			*/
-		0x00000400,
-		NO_VIDEO,
-		1, 0, 1, 0, 1,
-		NULL
-	},
-#endif
-#ifdef CONFIG_ARCH_RPC
-	{
-		MACH_TYPE_RISCPC,
-		"Acorn-RiscPC",	/* RMK			*/
-		0x10000100,
-		NO_VIDEO,
-		1, 1, 0, 0, 0,
-		fixup_acorn
-	},
+MACHINE_START(EBSA110, "EBSA110")
+	MAINTAINER("Russell King")
+	BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
+	BOOT_PARAMS(0x00000400)
+	DISABLE_PARPORT(0)
+	DISABLE_PARPORT(2)
+	SOFT_REBOOT
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_NEXUSPCI
-	{
-		MACH_TYPE_NEXUSPCI,
-		"FTV/PCI",	/* Philip Blundell	*/
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		NULL
-	},
-#endif
-#ifdef CONFIG_ARCH_EBSA285
-	{
-		MACH_TYPE_EBSA285,
-		"EBSA285",		/* RMK			*/
-		0x00000100,
-		0x000a0000, 0x000bffff,
-		0, 0, 0, 0, 0,
-		fixup_ebsa285
-	},
-#endif
-#ifdef CONFIG_ARCH_NETWINDER
-	{
-		MACH_TYPE_NETWINDER,
-		"Rebel-NetWinder",	/* RMK			*/
-		0x00000100,
-		0x000a0000, 0x000bffff,
-		1, 0, 1, 0, 0,
-		fixup_netwinder
-	},
-#endif
-#ifdef CONFIG_ARCH_CATS
-	{
-		MACH_TYPE_CATS,
-		"Chalice-CATS",	/* Philip Blundell	*/
-		NO_PARAMS,
-		0x000a0000, 0x000bffff,
-		0, 0, 0, 0, 1,
-		fixup_cats
-	},
+MACHINE_START(NEXUSPCI, "FTV/PCI")
+	MAINTAINER("Philip Blundell")
+	BOOT_MEM(0x40000000, 0x10000000, 0xe0000000)
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_TBOX
-	{
-		MACH_TYPE_TBOX,
-		"unknown-TBOX",	/* Philip Blundell	*/
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		NULL
-	},
-#endif
-#ifdef CONFIG_ARCH_CO285
-	{
-		MACH_TYPE_CO285,
-		"co-EBSA285",	/* Mark van Doesburg	*/
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		fixup_coebsa285
-	},
+MACHINE_START(TBOX, "unknown-TBOX")
+	MAINTAINER("Philip Blundell")
+	BOOT_MEM(0x80000000, 0x00400000, 0xe0000000)
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_CLPS7110
-	{
-		MACH_TYPE_CLPS7110,
-		"CL-PS7110",	/* Werner Almesberger	*/
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		NULL
-	},
-#endif
-#ifdef CONFIG_ARCH_ARC
-	{
-		MACH_TYPE_ARCHIMEDES,
-		"Acorn-Archimedes",/* RMK/DAG		*/
-		0x0207c000,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		fixup_acorn
-	},
-#endif
-#ifdef CONFIG_ARCH_A5K
-	{
-		MACH_TYPE_A5K,
-		"Acorn-A5000",	/* RMK/PB		*/
-		0x0207c000,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		fixup_acorn
-	},
+MACHINE_START(CLPS7110, "CL-PS7110")
+	MAINTAINER("Werner Almesberger")
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_ETOILE
-	{
-		MACH_TYPE_ETOILE,
-		"Etoile",		/* Alex de Vries	*/
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		NULL
-	},
+MACHINE_START(ETOILE, "Etoile")
+	MAINTAINER("Alex de Vries")
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_LACIE_NAS
-	{
-		MACH_TYPE_LACIE_NAS,
-		"LaCie_NAS",	/* Benjamin Herrenschmidt */
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		NULL
-	},
+MACHINE_START(LACIE_NAS, "LaCie_NAS")
+	MAINTAINER("Benjamin Herrenschmidt")
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_CLPS7500
-	{
-		MACH_TYPE_CLPS7500,
-		"CL-PS7500",	/* Philip Blundell	*/
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		NULL
-	},
+MACHINE_START(CLPS7500, "CL-PS7500")
+	MAINTAINER("Philip Blundell")
+	BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_SHARK
-	{
-		MACH_TYPE_SHARK,
-		"Shark",		/* Alexander Schulz	*/
-		NO_PARAMS,
-		0x06000000, 0x06000000+0x001fffff,
-		0, 0, 0, 0, 0,
-		NULL
-	},
-#endif
-#ifdef CONFIG_ARCH_SA1100
-	{
-		MACH_TYPE_SA1100,
-		"SA1100-based",	/* Nicolas Pitre	*/
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		fixup_sa1100
-	},
+MACHINE_START(SHARK, "Shark")
+	MAINTAINER("Alexander Schulz")
+	BOOT_MEM(0x08000000, 0x40000000, 0xe0000000)
+	VIDEO(0x06000000, 0x061fffff)
+MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_PERSONAL_SERVER
-	{
-		MACH_TYPE_PERSONAL_SERVER,
-		"Compaq Personal Server",
-		NO_PARAMS,
-		NO_VIDEO,
-		0, 0, 0, 0, 0,
-		NULL
-	}
+MACHINE_START(PERSONAL_SERVER, "Compaq Personal Server")
+	MAINTAINER("Jamey Hicks / George France")
+	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+	BOOT_PARAMS(0x00000100)
+MACHINE_END
 #endif
-};
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/arch.h linux/arch/arm/kernel/arch.h
--- v2.3.99-pre5/linux/arch/arm/kernel/arch.h	Tue Mar 14 19:10:38 2000
+++ linux/arch/arm/kernel/arch.h	Tue Apr 25 16:54:38 2000
@@ -1,9 +1,27 @@
+/*
+ * The size of struct machine_desc
+ *   (for assembler code)
+ */
+#define SIZEOF_MACHINE_DESC	40
+
+#ifndef __ASSEMBLY__
+
 struct machine_desc {
+	/*
+	 * Note! The first four elements are used
+	 * by assembler code in head-armv.S
+	 */
 	unsigned int	nr;		/* architecture number	*/
+	unsigned int	phys_ram;	/* start of physical ram */
+	unsigned int	phys_io;	/* start of physical io	*/
+	unsigned int	virt_io;	/* start of virtual io	*/
+
 	const char	*name;		/* architecture name	*/
 	unsigned int	param_offset;	/* parameter page	*/
+
 	unsigned int	video_start;	/* start of video RAM	*/
 	unsigned int	video_end;	/* end of video RAM	*/
+
 	unsigned int	reserve_lp0 :1;	/* never has lp0	*/
 	unsigned int	reserve_lp1 :1;	/* never has lp1	*/
 	unsigned int	reserve_lp2 :1;	/* never has lp2	*/
@@ -13,3 +31,43 @@
 				 struct param_struct *, char **,
 				 struct meminfo *);
 };
+
+/*
+ * Set of macros to define architecture features
+ */
+#define MACHINE_START(_type,_name)		\
+const struct machine_desc __mach_desc_##_type	\
+ __attribute__((__section__(".arch.info"))) = {	\
+	nr:		MACH_TYPE_##_type##,	\
+	name:		_name,
+
+#define MAINTAINER(n)
+
+#define BOOT_MEM(_pram,_pio,_vio)		\
+	phys_ram:	_pram,			\
+	phys_io:	_pio,			\
+	virt_io:	_vio,
+
+#define BOOT_PARAMS(_params)			\
+	param_offset:	_params,
+
+#define VIDEO(_start,_end)			\
+	video_start:	_start,			\
+	video_end:	_end,
+
+#define DISABLE_PARPORT(_n)			\
+	reserve_lp##_n##:	1,
+
+#define BROKEN_HLT				\
+	broken_hlt:	1,
+
+#define SOFT_REBOOT				\
+	soft_reboot:	1,
+
+#define FIXUP(_func)				\
+	fixup:		_func,
+
+#define MACHINE_END				\
+};
+
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.3.99-pre5/linux/arch/arm/kernel/armksyms.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/kernel/armksyms.c	Tue Apr 25 16:54:38 2000
@@ -101,6 +101,7 @@
 EXPORT_SYMBOL(system_rev);
 EXPORT_SYMBOL(system_serial_low);
 EXPORT_SYMBOL(system_serial_high);
+EXPORT_SYMBOL(mem_fclk_21285);
 EXPORT_SYMBOL(__bug);
 EXPORT_SYMBOL(__readwrite_bug);
 EXPORT_SYMBOL(enable_irq);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/arthur.c linux/arch/arm/kernel/arthur.c
--- v2.3.99-pre5/linux/arch/arm/kernel/arthur.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/kernel/arthur.c	Thu Apr 13 08:11:48 2000
@@ -59,11 +59,7 @@
 	PER_RISCOS, PER_RISCOS,
 	arthur_to_linux_signals,
 	linux_to_arthur_signals,
-#ifdef MODULE
-	&__this_module,	/* No usage counter. */
-#else
-	NULL,
-#endif
+	THIS_MODULE,
 	NULL		/* Nothing after this in the list. */
 };
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.3.99-pre5/linux/arch/arm/kernel/bios32.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/kernel/bios32.c	Tue Apr 25 16:54:38 2000
@@ -21,7 +21,7 @@
 
 extern void hw_init(void);
 
-void pcibios_report_device_errors(void)
+void pcibios_report_device_errors(int warn)
 {
 	struct pci_dev *dev;
 
@@ -34,8 +34,11 @@
 			continue;
 
 		pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
-		printk(KERN_DEBUG "PCI: %02X:%02X: status %04X on %s\n",
-			dev->bus->number, dev->devfn, status, dev->name);
+
+		if (warn)
+			printk(KERN_DEBUG "PCI: %02X:%02X: status %04X "
+			       "on %s\n", dev->bus->number, dev->devfn,
+			       status, dev->name);
 	}
 }
 
@@ -48,10 +51,6 @@
  * - (0x48) enable all memory requests from ISA to be channeled to PCI
  * - (0x42) disable ping-pong (as per errata)
  * - (0x40) enable PCI packet retry
- * - (0x44) Route INTA to IRQ11
- * - (0x83) don't use CPU park enable, park on last master, disable GAT bit
- * - (0x80) default rotating priorities
- * - (0x81) rotate bank 4
  */
 static void __init pci_fixup_83c553(struct pci_dev *dev)
 {
@@ -64,10 +63,26 @@
 	pci_write_config_byte(dev, 0x48, 0xff);
 	pci_write_config_byte(dev, 0x42, 0x00);
 	pci_write_config_byte(dev, 0x40, 0x22);
-	pci_write_config_word(dev, 0x44, 0xb000);
-	pci_write_config_byte(dev, 0x83, 0x02);
+
+	/*
+	 * We used to set the arbiter to "park on last master"
+	 * (bit 1 set), but unfortunately the CyberPro does not
+	 * park the bus.  We must therefore park on CPU.
+	 */
+	pci_write_config_byte(dev, 0x83, 0x00);
+
+	/*
+	 * Rotate priorities of each PCI request
+	 */
 	pci_write_config_byte(dev, 0x80, 0xe0);
 	pci_write_config_byte(dev, 0x81, 0x01);
+
+	/*
+	 * Route INTA input to IRQ 11, and set
+	 * IRQ11 to be level sensitive.
+	 */
+	pci_write_config_word(dev, 0x44, 0xb000);
+	outb(0x08, 0x4d1);
 }
 
 static void __init pci_fixup_unassign(struct pci_dev *dev)
@@ -77,6 +92,23 @@
 }
 
 /*
+ * Prevent the PCI layer from seeing the resources
+ * allocated to this device.  These resources are
+ * of no consequence to the PCI layer (they are
+ * handled elsewhere).
+ */
+static void __init pci_fixup_disable(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		dev->resource[i].start = 0;
+		dev->resource[i].end   = 0;
+		dev->resource[i].flags = 0;
+	}
+}
+
+/*
  * PCI IDE controllers use non-standard I/O port
  * decoding, respect it.
  */
@@ -100,6 +132,10 @@
 struct pci_fixup pcibios_fixups[] = {
 	{
 		PCI_FIXUP_HEADER,
+		PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_21285,
+		pci_fixup_disable
+	}, {
+		PCI_FIXUP_HEADER,
 		PCI_VENDOR_ID_WINBOND,	PCI_DEVICE_ID_WINBOND_83C553,
 		pci_fixup_83c553
 	}, {
@@ -339,6 +375,7 @@
 
 	case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000):
 	case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010):
+	case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000):
 		return IRQ_NETWINDER_VGA;
 
 	default:
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S
--- v2.3.99-pre5/linux/arch/arm/kernel/debug-armv.S	Fri Jan 21 18:19:15 2000
+++ linux/arch/arm/kernel/debug-armv.S	Tue Apr 25 16:54:38 2000
@@ -68,7 +68,10 @@
 #ifndef CONFIG_DEBUG_DC21285_PORT
 	/* For NetWinder debugging */
 		.macro	addruart,rx
-		mov	\rx, #0xff000000
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1			@ MMU enabled?
+		moveq	\rx, #0x7c000000	@ physical
+		movne	\rx, #0xff000000	@ virtual
 		orr	\rx, \rx, #0x000003f8
 		.endm
 
@@ -133,7 +136,10 @@
 
 #elif defined(CONFIG_ARCH_SA1100)
 		.macro	addruart,rx
-		mov	\rx, #0xf8000000
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1			@ MMU enabled?
+		moveq	\rx, #0x80000000	@ physical base address
+		movne	\rx, #0xf8000000	@ virtual address
 		add	\rx, \rx, #0x00050000	@ Ser3
 		@add	\rx, \rx, #0x00010000	@ Ser1
 		.endm
@@ -171,7 +177,7 @@
 
 ENTRY(printhex2)
 		mov	r1, #2
-printhex:	ldr	r2, =hexbuf
+printhex:	adr	r2, hexbuf
 		add	r3, r2, r1
 		mov	r1, #0
 		strb	r1, [r3]
@@ -209,5 +215,4 @@
 		mov	r0, #0
 		b	1b
 
-		.bss
 hexbuf:		.space 16
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c
--- v2.3.99-pre5/linux/arch/arm/kernel/dec21285.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/kernel/dec21285.c	Tue Apr 25 16:54:38 2000
@@ -23,18 +23,28 @@
 #define MAX_SLOTS		21
 
 extern int setup_arm_irq(int, struct irqaction *);
-extern void pcibios_report_device_errors(void);
+extern void pcibios_report_device_errors(int warn);
 
 static unsigned long
-dc21285_base_address(struct pci_dev *dev, int where)
+dc21285_base_address(struct pci_dev *dev)
 {
 	unsigned long addr = 0;
 	unsigned int devfn = dev->devfn;
 
-	if (dev->bus->number != 0)
+	if (dev->bus->number == 0) {
+		if (PCI_SLOT(devfn) == 0)
+			/*
+			 * For devfn 0, point at the 21285
+			 */
+			addr = ARMCSR_BASE;
+		else {
+			devfn -= 1 << 3;
+
+			if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
+				addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
+		}
+	} else
 		addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8);
-	else if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
-		addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
 
 	return addr;
 }
@@ -42,7 +52,7 @@
 static int
 dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value)
 {
-	unsigned long addr = dc21285_base_address(dev, where);
+	unsigned long addr = dc21285_base_address(dev);
 	u8 v;
 
 	if (addr)
@@ -59,7 +69,7 @@
 static int
 dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value)
 {
-	unsigned long addr = dc21285_base_address(dev, where);
+	unsigned long addr = dc21285_base_address(dev);
 	u16 v;
 
 	if (addr)
@@ -76,7 +86,7 @@
 static int
 dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
-	unsigned long addr = dc21285_base_address(dev, where);
+	unsigned long addr = dc21285_base_address(dev);
 	u32 v;
 
 	if (addr)
@@ -93,7 +103,7 @@
 static int
 dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value)
 {
-	unsigned long addr = dc21285_base_address(dev, where);
+	unsigned long addr = dc21285_base_address(dev);
 
 	if (addr)
 		asm("str%?b	%0, [%1, %2]"
@@ -105,7 +115,7 @@
 static int
 dc21285_write_config_word(struct pci_dev *dev, int where, u16 value)
 {
-	unsigned long addr = dc21285_base_address(dev, where);
+	unsigned long addr = dc21285_base_address(dev);
 
 	if (addr)
 		asm("str%?h	%0, [%1, %2]"
@@ -117,7 +127,7 @@
 static int
 dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value)
 {
-	unsigned long addr = dc21285_base_address(dev, where);
+	unsigned long addr = dc21285_base_address(dev);
 
 	if (addr)
 		asm("str%?	%0, [%1, %2]"
@@ -147,6 +157,9 @@
 	unsigned long irqstatus = *CSR_IRQ_RAWSTATUS;
 	int warn = time_after_eq(jiffies, next_warn);
 
+	if (machine_is_netwinder())
+		warn = 0;
+
 	ctrl |= SA110_CNTL_DISCARDTIMER;
 
 	if (warn) {
@@ -193,7 +206,7 @@
 	if (warn)
 		printk("pc=[<%08lX>]\n", instruction_pointer(regs));
 
-	pcibios_report_device_errors();
+	pcibios_report_device_errors(warn);
 
 	*CSR_PCICMD = cmd;
 	*CSR_SA110_CNTL = ctrl;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.3.99-pre5/linux/arch/arm/kernel/entry-common.S	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/kernel/entry-common.S	Tue Apr 25 16:54:38 2000
@@ -6,7 +6,7 @@
 #define S_OFF		8
 
 		.macro	get_softirq, rd
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #error SMP not supported
 #else
 		ldr	\rd, __softirq_state
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.3.99-pre5/linux/arch/arm/kernel/head-armv.S	Tue Mar 14 19:10:38 2000
+++ linux/arch/arm/kernel/head-armv.S	Tue Apr 25 16:54:38 2000
@@ -12,6 +12,8 @@
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 
+#include "arch.h"
+
 #if (TEXTADDR & 0xffff) != 0x8000
 #error TEXTADDR must start at 0xXXXX8000
 #endif
@@ -231,6 +233,13 @@
  * Generally, only serious errors cause this.
  */
 __error:
+#ifdef CONFIG_DEBUG_LL
+		mov	r8, r0				@ preserve r0
+		adr	r0, err_str
+		bl	printascii
+		mov	r0, r8
+		bl	printch
+#endif
 #ifdef CONFIG_ARCH_RPC
 /*
  * Turn the screen red on a error - RiscPC only.
@@ -247,7 +256,10 @@
 1:		mov	r0, r0
 		b	1b
 
-
+#ifdef CONFIG_DEBUG_LL
+err_str:	.asciz	"\nError: "
+		.align
+#endif
 
 /*
  * Read processor ID register (CP#15, CR0), and determine
@@ -262,9 +274,9 @@
 __lookup_processor_type:
 		adr	r5, 2f
 		ldmia	r5, {r7, r9, r10}
-		sub	r5, r5, r9
+		sub	r5, r5, r10
 		add	r7, r7, r5
-		add	r10, r10, r5
+		add	r10, r9, r5
 		mrc	p15, 0, r9, c0, c0		@ get processor id
 1:		ldmia	r10, {r5, r6, r8}		@ value, mask, mmuflags
 		eor	r5, r5, r9
@@ -277,8 +289,10 @@
 		mov	pc, lr
 
 2:		.long	__proc_info_end
-		.long	2b
 		.long	__proc_info_begin
+		.long	2b
+		.long	__arch_info_begin
+		.long	__arch_info_end
 
 /*
  * Lookup machine architecture
@@ -290,135 +304,18 @@
  *  r7 = byte offset into page tables for IO
  */
 __lookup_architecture_type:
-		cmp	r1, #(__arch_types_end - __arch_types_start) / 16
-		bge	1f
-		adr	r4, __arch_types_start
-		add	r4, r4, r1, lsl #4
-		ldmia	r4, {r4, r5, r6, r7}
-		mov	r7, r7, lsr #18
+		adr	r4, 2b
+		ldmia	r4, {r2, r3, r5, r6, r7}	@ throw away r2, r3
+		sub	r5, r4, r5
+		add	r4, r6, r5
+		add	r7, r7, r5
+1:		ldr	r5, [r4]
+		teq	r5, r1
+		beq	2f
+		add	r4, r4, #SIZEOF_MACHINE_DESC
+		cmp	r4, r7
+		blt	1b
+		mov	r7, #0
 		mov	pc, lr
-1:		mov	r7, #0
+2:		ldmib	r4, {r5, r6, r7}
 		mov	pc, lr
-
-/*
- * Machine parameters.  Each machine requires 4 words, which are:
- *
- * word0: unused
- * word1: physical start address of RAM
- * word2: physical start address of IO
- * word3: virtual start address of IO
- *
- * The IO mappings entered here are used to set up mappings
- * required for debugging information to be shown to the user.
- * paging_init() does the real page table initialisation.
- */
-		.type	__arch_types_start, #object
-		@ 0x00 - DEC EBSA110
-__arch_types_start:
-		.long	0
-		.long	0
-		.long	0xe0000000
-		.long	0xe0000000
-
-		@ 0x01 - Acorn RiscPC
-		.long	0
-		.long	0x10000000
-		.long	0x03000000
-		.long	0xe0000000
-
-		@ 0x02 - Unused
-		.long	0
-		.long	0
-		.long	0xe0000000
-		.long	0xe0000000
-
-		@ 0x03 - NexusPCI
-		.long	0
-		.long	0x40000000
-		.long	0x10000000
-		.long	0xe0000000
-
-		@ 0x04 - DEC EBSA285
-		.long	0
-		.long	0
-		.long	DC21285_ARMCSR_BASE
-		.long	0xfe000000
-
-		@ 0x05 - Rebel.com NetWinder
-		.long	0
-		.long	0
-		.long	DC21285_ARMCSR_BASE
-		.long	0xfe000000
-
-		@ 0x06 - CATS
-		.long	0
-		.long	0
-		.long	DC21285_ARMCSR_BASE
-		.long	0xfe000000
-
-		@ 0x07 - tbox
-		.long	0
-		.long	0x80000000
-		.long	0x00400000			@ Uart
-		.long	0xe0000000
-
-		@ 0x08 - DEC EBSA285 as co-processor
-		.long	0
-		.long	0
-		.long	DC21285_ARMCSR_BASE		@ Physical I/O base address
-		.long	0x7cf00000			@ Virtual I/O base address
-
-		@ 0x09 - CL-PS7110
-		.long	0
-		.long	0
-		.long	0
-		.long	0
-
-		@ 0x0a - Acorn Archimedes
-		.long	0
-		.long	0
-		.long	0
-		.long	0
-
-		@ 0x0b - Acorn A5000
-		.long	0
-		.long	0
-		.long	0
-		.long	0
-
-		@ 0x0c - Etoile
-		.long	0
-		.long	0
-		.long	0
-		.long	0
-
-		@ 0x0d - LaCie_NAS
-		.long	0
-		.long	0
-		.long	0
-		.long	0
-
-		@ 0x0e - CL-PS7500
-		.long	0
-		.long	0x10000000
-		.long	0x03000000
-		.long	0xe0000000
-
-		@ 0x0f - Digital Shark (DNARD)
-		.long	0
-		.long	0x08000000
-		.long	0x40000000
-		.long	0xe0000000
-
-		@ 0x10 - SA1100
-		.long	0
-		.long	0xc0000000
-		.long	0x80000000
-		.long	0xf8000000
-
-		/*
-		 * Don't add anything here unless you have an
-		 * architecture number allocated - see
-		 * Documentation/arm/README
-		 */
-__arch_types_end:
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.3.99-pre5/linux/arch/arm/kernel/irq.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/kernel/irq.c	Tue Apr 25 16:54:38 2000
@@ -118,10 +118,8 @@
 	cliIF();
 	irq_desc[irq].probing = 0;
 	irq_desc[irq].triggered = 0;
-	if (!irq_desc[irq].noautoenable) {
-		irq_desc[irq].enabled = 1;
-		irq_desc[irq].unmask(irq);
-	}
+	irq_desc[irq].enabled = 1;
+	irq_desc[irq].unmask(irq);
 	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.3.99-pre5/linux/arch/arm/kernel/setup.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/kernel/setup.c	Tue Apr 25 16:54:39 2000
@@ -5,15 +5,14 @@
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/mm.h>
 #include <linux/stddef.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/utsname.h>
 #include <linux/blk.h>
 #include <linux/console.h>
-#include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/init.h>
 
 #include <asm/elf.h>
 #include <asm/hardware.h>
@@ -33,6 +32,7 @@
 #endif
 
 extern void paging_init(struct meminfo *);
+extern void bootmem_init(struct meminfo *);
 extern void reboot_setup(char *str);
 extern void disable_hlt(void);
 extern int root_mountflags;
@@ -43,6 +43,7 @@
 unsigned int system_rev;
 unsigned int system_serial_low;
 unsigned int system_serial_high;
+unsigned int mem_fclk_21285 = 50000000;
 unsigned int elf_hwcap;
 
 #ifdef MULTI_CPU
@@ -199,7 +200,8 @@
 			if (to != command_line)
 				to -= 1;
 
-			/* If the user specifies memory size, we
+			/*
+			 * If the user specifies memory size, we
 			 * blow away any automatically generated
 			 * size.
 			 */
@@ -256,137 +258,6 @@
 #endif
 }
 
-#define O_PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define V_PFN_DOWN(x)	O_PFN_DOWN(__pa(x))
-
-#define O_PFN_UP(x)	(PAGE_ALIGN(x) >> PAGE_SHIFT)
-#define V_PFN_UP(x)	O_PFN_UP(__pa(x))
-
-#define PFN_SIZE(x)	((x) >> PAGE_SHIFT)
-#define PFN_RANGE(s,e)	PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \
-				(((unsigned long)(s)) & PAGE_MASK))
-
-/*
- * FIXME: These can be removed when Ingo's cleanup patch goes in
- */
-#define free_bootmem(s,sz)	free_bootmem((s)<<PAGE_SHIFT, (sz)<<PAGE_SHIFT)
-#define reserve_bootmem(s,sz)	reserve_bootmem((s)<<PAGE_SHIFT, (sz)<<PAGE_SHIFT)
-
-static unsigned int __init
-find_bootmap_pfn(struct meminfo *mi, unsigned int bootmap_pages)
-{
-	unsigned int start_pfn, bank, bootmap_pfn;
-
-	start_pfn   = V_PFN_UP(&_end);
-	bootmap_pfn = 0;
-
-	/*
-	 * FIXME: We really want to avoid allocating the bootmap
-	 * over the top of the initrd.
-	 */
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start) {
-		if (__pa(initrd_end) > mi->end) {
-			printk ("initrd extends beyond end of memory "
-				"(0x%08lx > 0x%08lx) - disabling initrd\n",
-				__pa(initrd_end), mi->end);
-			initrd_start = 0;
-			initrd_end   = 0;
-		}
-	}
-#endif
-
-	for (bank = 0; bank < mi->nr_banks; bank ++) {
-		unsigned int start, end;
-
-		if (mi->bank[bank].size == 0)
-			continue;
-
-		start = O_PFN_UP(mi->bank[bank].start);
-		end   = O_PFN_DOWN(mi->bank[bank].size +
-				   mi->bank[bank].start);
-
-		if (end < start_pfn)
-			continue;
-
-		if (start < start_pfn)
-			start = start_pfn;
-
-		if (end <= start)
-			continue;
-
-		if (end - start >= bootmap_pages) {
-			bootmap_pfn = start;
-			break;
-		}
-	}
-
-	if (bootmap_pfn == 0)
-		BUG();
-
-	return bootmap_pfn;
-}
-
-/*
- * Initialise the bootmem allocator.
- */
-static void __init setup_bootmem(struct meminfo *mi)
-{
-	unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn;
-	unsigned int i;
-
-	/*
-	 * Calculate the  physical address of the top of memory.
-	 */
-	mi->end = 0;
-	for (i = 0; i < mi->nr_banks; i++) {
-		unsigned long end;
-
-		if (mi->bank[i].size != 0) {
-			end = mi->bank[i].start + mi->bank[i].size;
-			if (mi->end < end)
-				mi->end = end;
-		}
-	}
-
-	start_pfn     = O_PFN_UP(PHYS_OFFSET);
-	end_pfn	      = O_PFN_DOWN(mi->end);
-	bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
-	bootmap_pfn   = find_bootmap_pfn(mi, bootmap_pages);
-
-	/*
-	 * Initialise the boot-time allocator
-	 */
-	init_bootmem_start(bootmap_pfn, start_pfn, end_pfn);
-
-	/*
-	 * Register all available RAM with the bootmem allocator.
-	 */
-	for (i = 0; i < mi->nr_banks; i++)
-		if (mi->bank[i].size)
-			free_bootmem(O_PFN_UP(mi->bank[i].start),
-				     PFN_SIZE(mi->bank[i].size));
-
-	/*
-	 * Register the reserved regions with bootmem
-	 */
-	reserve_bootmem(bootmap_pfn, bootmap_pages);
-	reserve_bootmem(V_PFN_DOWN(&_stext), PFN_RANGE(&_stext, &_end));
-
-#ifdef CONFIG_CPU_32
-	/*
-	 * Reserve the page tables.  These are already in use.
-	 */
-	reserve_bootmem(V_PFN_DOWN(swapper_pg_dir),
-			PFN_SIZE(PTRS_PER_PGD * sizeof(void *)));
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start)
-		reserve_bootmem(V_PFN_DOWN(initrd_start),
-				PFN_RANGE(initrd_start, initrd_end));
-#endif
-}
-
 static void __init
 request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
 {
@@ -487,6 +358,9 @@
 		system_serial_low  = params->u1.s.system_serial_low;
 		system_serial_high = params->u1.s.system_serial_high;
 
+		if (params->u1.s.mem_fclk_21285 > 0)
+			mem_fclk_21285 = params->u1.s.mem_fclk_21285;  
+
 		setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0,
 			      (params->u1.s.flags & FLAG_RDPROMPT) == 0,
 			      params->u1.s.rd_start,
@@ -518,9 +392,8 @@
 	memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
 	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 	parse_cmdline(&meminfo, cmdline_p, from);
-	setup_bootmem(&meminfo);
+	bootmem_init(&meminfo);
 	request_standard_resources(&meminfo, mdesc);
-
 	paging_init(&meminfo);
 
 #ifdef CONFIG_VT
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c
--- v2.3.99-pre5/linux/arch/arm/kernel/time.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/arm/kernel/time.c	Tue Apr 25 16:54:39 2000
@@ -30,6 +30,7 @@
 
 extern int setup_arm_irq(int, struct irqaction *);
 extern void setup_timer(void);
+extern rwlock_t xtime_lock;
 extern volatile unsigned long lost_ticks;
 
 /* change this if you have some constant time drift */
@@ -59,7 +60,8 @@
 }
 
 /*
- * hook for getting the time offset
+ * hook for getting the time offset.  Note that it is
+ * always called with interrupts disabled.
  */
 unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset;
 
@@ -175,29 +177,33 @@
 void do_gettimeofday(struct timeval *tv)
 {
 	unsigned long flags;
+	unsigned long usec, sec;
 
-	save_flags_cli (flags);
-	*tv = xtime;
-	tv->tv_usec += gettimeoffset();
-
-	/*
-	 * xtime is atomically updated in timer_bh. lost_ticks is
-	 * nonzero if the timer bottom half hasnt executed yet.
-	 */
-	if (lost_ticks)
-		tv->tv_usec += USECS_PER_JIFFY;
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = gettimeoffset();
+	{
+		unsigned long lost = lost_ticks;
 
-	restore_flags(flags);
+		if (lost)
+			usec += lost * USECS_PER_JIFFY;
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
+	read_unlock_irqrestore(&xtime_lock, flags);
 
-	if (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
+	/* usec may have gone up a lot: be safe */
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
 	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 void do_settimeofday(struct timeval *tv)
 {
-	cli ();
+	write_lock_irq(&xtime_lock);
 	/* This is revolting. We need to set the xtime.tv_usec
 	 * correctly. However, the value in this location is
 	 * is value at the last tick.
@@ -205,8 +211,9 @@
 	 * would have done, and then undo it!
 	 */
 	tv->tv_usec -= gettimeoffset();
+	tv->tv_usec -= lost_ticks * USECS_PER_JIFFY;
 
-	if (tv->tv_usec < 0) {
+	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
 		tv->tv_sec--;
 	}
@@ -216,7 +223,7 @@
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	write_unlock_irq(&xtime_lock);
 }
 
 static struct irqaction timer_irq = {
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopy.S linux/arch/arm/lib/csumpartialcopy.S
--- v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopy.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/arm/lib/csumpartialcopy.S	Tue Apr 25 16:54:39 2000
@@ -12,16 +12,46 @@
  * Params  : r0 = src, r1 = dst, r2 = len, r3 = checksum
  * Returns : r0 = new checksum
  */
+
+		.macro	save_regs
+		stmfd	sp!, {r4 - r8, fp, ip, lr, pc}
+		.endm
+
+		.macro	load_regs,flags
+		LOADREGS(\flags,fp,{r4 - r8, fp, sp, pc})
+		.endm
+
+		.macro	load1b, reg1
+		ldrb	\reg1, [r0], #1
+		.endm
+
+		.macro	load2b, reg1, reg2
+		ldrb	\reg1, [r0], #1
+		ldrb	\reg2, [r0], #1
+		.endm
+
+		.macro	load1l, reg1
+		ldr	\reg1, [r0], #4
+		.endm
+
+		.macro	load2l, reg1, reg2
+		ldr	\reg1, [r0], #4
+		ldr	\reg2, [r0], #4
+		.endm
+
+		.macro	load4l, reg1, reg2, reg3, reg4
+		ldmia	r0!, {\reg1, \reg2, \reg3, \reg4}
+		.endm
+
 ENTRY(csum_partial_copy_nocheck)
 		mov	ip, sp
-		stmfd	sp!, {r4 - r8, fp, ip, lr, pc}
+		save_regs
 		sub	fp, ip, #4
 		cmp	r2, #4
-		blt	Ltoo_small
+		blt	.too_small
 		tst	r1, #2			@ Test destination alignment
-		beq	Ldst_aligned
-		ldrb	ip, [r0], #1
-		ldrb	r8, [r0], #1
+		beq	.dst_aligned
+		load2b	ip, r8
 		subs	r2, r2, #2		@ We do not know if SRC is aligned...
 		orr	ip, ip, r8, lsl #8
 		adds	r3, r3, ip
@@ -29,12 +59,12 @@
 		strb	ip, [r1], #1
 		mov	ip, ip, lsr #8
 		strb	ip, [r1], #1		@ Destination now aligned
-Ldst_aligned:	tst	r0, #3
-		bne	Lsrc_not_aligned
+.dst_aligned:	tst	r0, #3
+		bne	.src_not_aligned
 		adds	r3, r3, #0
 		bics	ip, r2, #15		@ Routine for src & dst aligned
-		beq	3f
-1:		ldmia	r0!, {r4, r5, r6, r7}
+		beq	2f
+1:		load4l	r4, r5, r6, r7
 		stmia	r1!, {r4, r5, r6, r7}
 		adcs	r3, r3, r4
 		adcs	r3, r3, r5
@@ -43,65 +73,69 @@
 		sub	ip, ip, #16
 		teq	ip, #0
 		bne	1b
-3:		ands	ip, r2, #12
-		beq	5f
-		tst	ip, #8
+2:		ands	ip, r2, #12
 		beq	4f
-		ldmia	r0!, {r4, r5}
+		tst	ip, #8
+		beq	3f
+		load2l	r4, r5
 		stmia	r1!, {r4, r5}
 		adcs	r3, r3, r4
 		adcs	r3, r3, r5
 		tst	ip, #4
-		beq	5f
-4:		ldr	r4, [r0], #4
+		beq	4f
+3:		load1l	r4
 		str	r4, [r1], #4
 		adcs	r3, r3, r4
-5:		ands	r2, r2, #3
+4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
-		ldr	r4, [r0], #4
+		load_regs	eqea
+		load1l	r4
 		tst	r2, #2
-		beq	Lexit_r4
+		beq	.exit
 		adcs	r3, r3, r4, lsl #16
 		strb	r4, [r1], #1
 		mov	r4, r4, lsr #8
 		strb	r4, [r1], #1
 		mov	r4, r4, lsr #8
-		b	Lexit_r4
+.exit:		tst	r2, #1
+		strneb	r4, [r1], #1
+		andne	r4, r4, #255
+		adcnes	r3, r3, r4
+		adcs	r0, r3, #0
+		load_regs	ea
 
-Ltoo_small:	teq	r2, #0
-		LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+.too_small:	teq	r2, #0
+		load_regs	eqea
 		cmp	r2, #2
-		blt	Ltoo_small1
-		ldrb	ip, [r0], #1
-		ldrb	r8, [r0], #1
+		blt	.too_small1
+		load2b	ip, r8
 		orr	ip, ip, r8, lsl #8
 		adds	r3, r3, ip
 		strb	ip, [r1], #1
 		strb	r8, [r1], #1
 		tst	r2, #1
-Ltoo_small1:	ldrneb	r4, [r0], #1
-Lexit_r4:	tst	r2, #1
-		strneb	r4, [r1], #1
-		andne	r4, r4, #255
-		adcnes	r3, r3, r4
-		adcs	r0, r3, #0
-		LOADREGS(ea,fp,{r4 - r8, fp, sp, pc})
+.too_small1:				@ C = 0
+		beq	.csum_exit
+		load1b	ip
+		strb	ip, [r1], #1
+		adcs	r3, r3, ip
+.csum_exit:	adc	r0, r3, #0
+		load_regs	ea
 
-Lsrc_not_aligned:
+.src_not_aligned:
 		cmp	r2, #4
-		blt	Ltoo_small
+		blt	.too_small
 		and	ip, r0, #3
 		bic	r0, r0, #3
-		ldr	r4, [r0], #4
+		load1l	r4
 		cmp	ip, #2
-		beq	Lsrc2_aligned
-		bhi	Lsrc3_aligned
+		beq	.src2_aligned
+		bhi	.src3_aligned
 		mov	r4, r4, lsr #8
 		adds	r3, r3, #0
 		bics	ip, r2, #15
 		beq	2f
-1:		ldmia	r0!, {r5, r6, r7, r8}
+1:		load4l	r5, r6, r7, r8
 		orr	r4, r4, r5, lsl #24
 		mov	r5, r5, lsr #8
 		orr	r5, r5, r6, lsl #24
@@ -122,7 +156,7 @@
 		beq	4f
 		tst	ip, #8
 		beq	3f
-		ldmia	r0!, {r5, r6}
+		load2l	r5, r6
 		orr	r4, r4, r5, lsl #24
 		mov	r5, r5, lsr #8
 		orr	r5, r5, r6, lsl #24
@@ -132,28 +166,28 @@
 		mov	r4, r6, lsr #8
 		tst	ip, #4
 		beq	4f
-3:		ldr	r5, [r0], #4
+3:		load1l	r5
 		orr	r4, r4, r5, lsl #24
 		str	r4, [r1], #4
 		adcs	r3, r3, r4
 		mov	r4, r5, lsr #8
 4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+		load_regs	eqea
 		tst	r2, #2
-		beq	Lexit_r4
+		beq	.exit
 		adcs	r3, r3, r4, lsl #16
 		strb	r4, [r1], #1
 		mov	r4, r4, lsr #8
 		strb	r4, [r1], #1
 		mov	r4, r4, lsr #8
-		b	Lexit_r4
+		b	.exit
 
-Lsrc2_aligned:	mov	r4, r4, lsr #16
+.src2_aligned:	mov	r4, r4, lsr #16
 		adds	r3, r3, #0
 		bics	ip, r2, #15
 		beq	2f
-1:		ldmia	r0!, {r5, r6, r7, r8}
+1:		load4l	r5, r6, r7, r8
 		orr	r4, r4, r5, lsl #16
 		mov	r5, r5, lsr #16
 		orr	r5, r5, r6, lsl #16
@@ -174,7 +208,7 @@
 		beq	4f
 		tst	ip, #8
 		beq	3f
-		ldmia	r0!, {r5, r6}
+		load2l	r5, r6
 		orr	r4, r4, r5, lsl #16
 		mov	r5, r5, lsr #16
 		orr	r5, r5, r6, lsl #16
@@ -184,28 +218,31 @@
 		mov	r4, r6, lsr #16
 		tst	ip, #4
 		beq	4f
-3:		ldr	r5, [r0], #4
+3:		load1l	r5
 		orr	r4, r4, r5, lsl #16
 		str	r4, [r1], #4
 		adcs	r3, r3, r4
 		mov	r4, r5, lsr #16
 4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+		load_regs	eqea
 		tst	r2, #2
-		beq	Lexit_r4
+		beq	.exit
 		adcs	r3, r3, r4, lsl #16
 		strb	r4, [r1], #1
 		mov	r4, r4, lsr #8
 		strb	r4, [r1], #1
-		ldrb	r4, [r0], #1
-		b	Lexit_r4
+		tst	r2, #1
+		adceq	r0, r3, #0
+		load_regs	eqea
+		load1b	r4
+		b	.exit
 
-Lsrc3_aligned:	mov	r4, r4, lsr #24
+.src3_aligned:	mov	r4, r4, lsr #24
 		adds	r3, r3, #0
 		bics	ip, r2, #15
 		beq	2f
-1:		ldmia	r0!, {r5, r6, r7, r8}
+1:		load4l	r5, r6, r7, r8
 		orr	r4, r4, r5, lsl #8
 		mov	r5, r5, lsr #24
 		orr	r5, r5, r6, lsl #8
@@ -226,7 +263,7 @@
 		beq	4f
 		tst	ip, #8
 		beq	3f
-		ldmia	r0!, {r5, r6}
+		load2l	r5, r6
 		orr	r4, r4, r5, lsl #8
 		mov	r5, r5, lsr #24
 		orr	r5, r5, r6, lsl #8
@@ -236,22 +273,20 @@
 		mov	r4, r6, lsr #24
 		tst	ip, #4
 		beq	4f
-3:		ldr	r5, [r0], #4
+3:		load1l	r5
 		orr	r4, r4, r5, lsl #8
 		str	r4, [r1], #4
 		adcs	r3, r3, r4
 		mov	r4, r5, lsr #24
 4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+		load_regs	eqea
 		tst	r2, #2
-		beq	Lexit_r4
+		beq	.exit
 		adcs	r3, r3, r4, lsl #16
 		strb	r4, [r1], #1
-		ldr	r4, [r0], #4
+		load1l	r4
 		strb	r4, [r1], #1
 		adcs	r3, r3, r4, lsl #24
 		mov	r4, r4, lsr #8
-		b	Lexit_r4
-
-
+		b	.exit
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopyuser.S linux/arch/arm/lib/csumpartialcopyuser.S
--- v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopyuser.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/arm/lib/csumpartialcopyuser.S	Tue Apr 25 16:54:39 2000
@@ -153,9 +153,9 @@
 		save_regs
 		sub	fp, ip, #4
 		cmp	r2, #4
-		blt	.too_small_user
+		blt	.too_small
 		tst	r1, #2			@ Test destination alignment
-		beq	.dst_aligned_user
+		beq	.dst_aligned
 		load2b	ip, r8
 		subs	r2, r2, #2		@ We do not know if SRC is aligned...
 		orr	ip, ip, r8, lsl #8
@@ -164,9 +164,8 @@
 		strb	ip, [r1], #1
 		mov	ip, ip, lsr #8
 		strb	ip, [r1], #1		@ Destination now aligned
-.dst_aligned_user:
-		tst	r0, #3
-		bne	.src_not_aligned_user
+.dst_aligned:	tst	r0, #3
+		bne	.src_not_aligned
 		adds	r3, r3, #0
 		bics	ip, r2, #15		@ Routine for src & dst aligned
 		beq	2f
@@ -210,18 +209,17 @@
 		adcs	r0, r3, #0
 		load_regs	ea
 
-.too_small_user:
-		teq	r2, #0
+.too_small:	teq	r2, #0
 		load_regs	eqea
 		cmp	r2, #2
-		blt	.too_small_user1
+		blt	.too_small1
 		load2b	ip, r8
 		orr	ip, ip, r8, lsl #8
 		adds	r3, r3, ip
 		strb	ip, [r1], #1
 		strb	r8, [r1], #1
 		tst	r2, #1
-.too_small_user1:				@ C = 0
+.too_small1:				@ C = 0
 		beq	.csum_exit
 		load1b	ip
 		strb	ip, [r1], #1
@@ -229,15 +227,15 @@
 .csum_exit:	adc	r0, r3, #0
 		load_regs	ea
 
-.src_not_aligned_user:
+.src_not_aligned:
 		cmp	r2, #4
-		blt	.too_small_user
+		blt	.too_small
 		and	ip, r0, #3
 		bic	r0, r0, #3
 		load1l	r4
 		cmp	ip, #2
-		beq	.src2_aligned_user
-		bhi	.src3_aligned_user
+		beq	.src2_aligned
+		bhi	.src3_aligned
 		mov	r4, r4, lsr #8
 		adds	r3, r3, #0
 		bics	ip, r2, #15
@@ -290,8 +288,7 @@
 		mov	r4, r4, lsr #8
 		b	.exit
 
-.src2_aligned_user:
-		mov	r4, r4, lsr #16
+.src2_aligned:	mov	r4, r4, lsr #16
 		adds	r3, r3, #0
 		bics	ip, r2, #15
 		beq	2f
@@ -346,8 +343,7 @@
 		load1b	r4
 		b	.exit
 
-.src3_aligned_user:
-		mov	r4, r4, lsr #24
+.src3_aligned:	mov	r4, r4, lsr #24
 		adds	r3, r3, #0
 		bics	ip, r2, #15
 		beq	2f
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c
--- v2.3.99-pre5/linux/arch/arm/mm/consistent.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/mm/consistent.c	Tue Apr 25 16:54:39 2000
@@ -29,20 +29,29 @@
 	if (in_interrupt())
 		BUG();
 
+	size = PAGE_ALIGN(size);
 	order = get_order(size);
 
 	page = __get_free_pages(gfp, order);
 	if (!page)
 		goto no_page;
 
-	memset((void *)page, 0, PAGE_SIZE << order);
-	clean_cache_area(page, PAGE_SIZE << order);
+	memset((void *)page, 0, size);
+	clean_cache_area(page, size);
 
 	*dma_handle = virt_to_bus((void *)page);
 
-	ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0);
-	if (ret)
+	ret = __ioremap(virt_to_phys((void *)page), size, 0);
+	if (ret) {
+		/* free wasted pages */
+		unsigned long end = page + (PAGE_SIZE << order);
+		page += size;
+		while (page < end) {
+			free_page(page);
+			page += PAGE_SIZE;
+		}
 		return ret;
+	}
 
 	free_pages(page, order);
 no_page:
@@ -81,18 +90,18 @@
 /*
  * make an area consistent.
  */
-void consistent_sync(void *vaddr, size_t size, int rw)
+void consistent_sync(void *vaddr, size_t size, int direction)
 {
-	switch (rw) {
-	case 0:
+	switch (direction) {
+	case PCI_DMA_NONE:
 		BUG();
-	case 1:	/* invalidate only */
+	case PCI_DMA_FROMDEVICE:	/* invalidate only */
 		dma_cache_inv(vaddr, size);
 		break;
-	case 2:	/* writeback only */
+	case PCI_DMA_TODEVICE:		/* writeback only */
 		dma_cache_wback(vaddr, size);
 		break;
-	case 3:	/* writeback and invalidate */
+	case PCI_DMA_BIDIRECTIONAL:	/* writeback and invalidate */
 		dma_cache_wback_inv(vaddr, size);
 		break;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.3.99-pre5/linux/arch/arm/mm/fault-common.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/mm/fault-common.c	Mon Apr 24 15:51:52 2000
@@ -123,7 +123,7 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode)))
+	if (!handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(mode)))
 		goto do_sigbus;
 
 	up(&mm->mmap_sem);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.3.99-pre5/linux/arch/arm/mm/init.c	Tue Mar 14 19:10:39 2000
+++ linux/arch/arm/mm/init.c	Tue Apr 25 16:54:39 2000
@@ -1,9 +1,8 @@
 /*
  *  linux/arch/arm/mm/init.c
  *
- *  Copyright (C) 1995-1999 Russell King
+ *  Copyright (C) 1995-2000 Russell King
  */
-
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -32,9 +31,22 @@
 
 #include "map.h"
 
+#ifdef CONFIG_CPU_32
+#define TABLE_OFFSET	(PTRS_PER_PTE)
+#else
+#define TABLE_OFFSET	0
+#endif
+#define TABLE_SIZE	((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *))
+
 static unsigned long totalram_pages;
-struct meminfo meminfo;
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern int _stext, _text, _etext, _edata, _end;
+
+/*
+ * The sole use of this is to pass memory configuration
+ * data from paging_init to mem_init.
+ */
+static struct meminfo __initdata meminfo;
 
 /*
  * empty_bad_page is the page that is used for page faults when
@@ -119,33 +131,36 @@
 void show_mem(void)
 {
 	int free = 0, total = 0, reserved = 0;
-	int shared = 0, cached = 0;
-	struct page *page, *end;
+	int shared = 0, cached = 0, node;
 
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
 
-	page = mem_map;
-	end  = mem_map + max_mapnr;
+	for (node = 0; node < numnodes; node++) {
+		struct page *page, *end;
 
-	do {
-		if (PageSkip(page)) {
-			page = page->next_hash;
-			if (page == NULL)
-				break;
-		}
-		total++;
-		if (PageReserved(page))
-			reserved++;
-		else if (PageSwapCache(page))
-			cached++;
-		else if (!page_count(page))
-			free++;
-		else
-			shared += atomic_read(&page->count) - 1;
-		page++;
-	} while (page < end);
+		page = NODE_MEM_MAP(node);
+		end  = page + NODE_DATA(node)->node_size;
+
+		do {
+			if (PageSkip(page)) {
+				page = page->next_hash;
+				if (page == NULL)
+					break;
+			}
+			total++;
+			if (PageReserved(page))
+				reserved++;
+			else if (PageSwapCache(page))
+				cached++;
+			else if (!page_count(page))
+				free++;
+			else
+				shared += atomic_read(&page->count) - 1;
+			page++;
+		} while (page < end);
+	}
 
 	printk("%d pages of RAM\n", total);
 	printk("%d free pages\n", free);
@@ -158,24 +173,173 @@
 	show_buffers();
 }
 
+#define O_PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define V_PFN_DOWN(x)	O_PFN_DOWN(__pa(x))
+
+#define O_PFN_UP(x)	(PAGE_ALIGN(x) >> PAGE_SHIFT)
+#define V_PFN_UP(x)	O_PFN_UP(__pa(x))
+
+#define PFN_SIZE(x)	((x) >> PAGE_SHIFT)
+#define PFN_RANGE(s,e)	PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \
+				(((unsigned long)(s)) & PAGE_MASK))
+
+static unsigned int __init
+find_bootmap_pfn(struct meminfo *mi, unsigned int bootmap_pages)
+{
+	unsigned int start_pfn, bank, bootmap_pfn;
+
+	start_pfn   = V_PFN_UP(&_end);
+	bootmap_pfn = 0;
+
+	/*
+	 * FIXME: We really want to avoid allocating the bootmap
+	 * over the top of the initrd.
+	 */
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start) {
+		if (__pa(initrd_end) > mi->end) {
+			printk ("initrd extends beyond end of memory "
+				"(0x%08lx > 0x%08lx) - disabling initrd\n",
+				__pa(initrd_end), mi->end);
+			initrd_start = 0;
+			initrd_end   = 0;
+		}
+	}
+#endif
+
+	for (bank = 0; bank < mi->nr_banks; bank ++) {
+		unsigned int start, end;
+
+		if (mi->bank[bank].size == 0)
+			continue;
+
+		start = O_PFN_UP(mi->bank[bank].start);
+		end   = O_PFN_DOWN(mi->bank[bank].size +
+				   mi->bank[bank].start);
+
+		if (end < start_pfn)
+			continue;
+
+		if (start < start_pfn)
+			start = start_pfn;
+
+		if (end <= start)
+			continue;
+
+		if (end - start >= bootmap_pages) {
+			bootmap_pfn = start;
+			break;
+		}
+	}
+
+	if (bootmap_pfn == 0)
+		BUG();
+
+	return bootmap_pfn;
+}
+
+/*
+ * Initialise one node of the bootmem allocator.  For now, we
+ * only initialise node 0.  Notice that we have a bootmem
+ * bitmap per node.
+ */
+static void __init setup_bootmem_node(int node, struct meminfo *mi)
+{
+	unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn;
+	unsigned int i;
+
+	if (node != 0)	/* only initialise node 0 for now */
+		return;
+
+	start_pfn     = O_PFN_UP(PHYS_OFFSET);
+	end_pfn	      = O_PFN_DOWN(mi->end);
+	bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
+	bootmap_pfn   = find_bootmap_pfn(mi, bootmap_pages);
+
+	/*
+	 * Initialise the boot-time allocator
+	 */
+	init_bootmem_node(node, bootmap_pfn, start_pfn, end_pfn);
+
+	/*
+	 * Register all available RAM with the bootmem allocator.
+	 */
+	for (i = 0; i < mi->nr_banks; i++)
+		if (mi->bank[i].size)
+			free_bootmem_node(node, mi->bank[i].start,
+					  PFN_SIZE(mi->bank[i].size) << PAGE_SHIFT);
+
+	reserve_bootmem_node(node, bootmap_pfn << PAGE_SHIFT,
+			     bootmap_pages << PAGE_SHIFT);
+}
+
+/*
+ * Initialise the bootmem allocator.
+ */
+void __init bootmem_init(struct meminfo *mi)
+{
+	unsigned int i, node;
+
+	/*
+	 * Calculate the  physical address of the top of memory.
+	 * Note that there are no guarantees assumed about the
+	 * ordering of the bank information.
+	 */
+	mi->end = 0;
+	for (i = 0; i < mi->nr_banks; i++) {
+		unsigned long end;
+
+		if (mi->bank[i].size != 0) {
+			end = mi->bank[i].start + mi->bank[i].size;
+			if (mi->end < end)
+				mi->end = end;
+		}
+	}
+
+	max_low_pfn = O_PFN_DOWN(mi->end - PHYS_OFFSET);
+
+	/*
+	 * Setup each node
+	 */
+	for (node = 0; node < numnodes; node++)
+		setup_bootmem_node(node, mi);
+
+	/*
+	 * Register the kernel text and data with bootmem.
+	 * Note that this can only be in node 0.
+	 */
+	reserve_bootmem_node(0, V_PFN_DOWN(&_stext) << PAGE_SHIFT,
+			     PFN_RANGE(&_stext, &_end) << PAGE_SHIFT);
+
+#ifdef CONFIG_CPU_32
+	/*
+	 * Reserve the page tables.  These are already in use,
+	 * and can only be in node 0.
+	 */
+	reserve_bootmem_node(0, V_PFN_DOWN(swapper_pg_dir) << PAGE_SHIFT,
+			     PFN_SIZE(PTRS_PER_PGD * sizeof(void *)) << PAGE_SHIFT);
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+	/*
+	 * This may be in any bank.  Currently, we assume that
+	 * it is in bank 0.
+	 */
+	if (initrd_start)
+		reserve_bootmem_node(0, V_PFN_DOWN(initrd_start) << PAGE_SHIFT,
+				     PFN_RANGE(initrd_start, initrd_end) << PAGE_SHIFT);
+#endif
+}
+
 /*
  * paging_init() sets up the page tables...
  */
 void __init paging_init(struct meminfo *mi)
 {
 	void *zero_page, *bad_page, *bad_table;
-	unsigned long zone_size[MAX_NR_ZONES];
-	int i;
+	int node;
 
 	memcpy(&meminfo, mi, sizeof(meminfo));
 
-#ifdef CONFIG_CPU_32
-#define TABLE_OFFSET	(PTRS_PER_PTE)
-#else
-#define TABLE_OFFSET	0
-#endif
-#define TABLE_SIZE	((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *))
-
 	/*
 	 * allocate what we need for the bad pages
 	 */
@@ -186,31 +350,42 @@
 	/*
 	 * initialise the page tables
 	 */
-	pagetable_init();
+	pagetable_init(mi);
 	flush_tlb_all();
 
 	/*
-	 * Initialise the zones and mem_map
+	 * initialise the zones within each node
 	 */
-	for (i = 0; i < MAX_NR_ZONES; i++)
-		zone_size[i] = 0;
+	for (node = 0; node < numnodes; node++) {
+		unsigned long zone_size[MAX_NR_ZONES];
+		unsigned long zhole_size[MAX_NR_ZONES];
+		struct bootmem_data *bdata;
+		pg_data_t *pgdat;
+		int i;
+
+		/*
+		 * Initialise the zone size information.
+		 */
+		for (i = 0; i < MAX_NR_ZONES; i++) {
+			zone_size[i]  = 0;
+			zhole_size[i] = 0;
+		}
 
-	/*
-	 * Calculate the size of the zones.  On ARM, we don't have
-	 * any problems with DMA or highmem, so all memory is
-	 * allocated to the DMA zone.
-	 */
-	for (i = 0; i < mi->nr_banks; i++) {
-		if (mi->bank[i].size) {
-			unsigned int end;
+		pgdat = NODE_DATA(node);
+		bdata = pgdat->bdata;
 
-			end = (mi->bank[i].start - PHYS_OFFSET +
-			       mi->bank[i].size) >> PAGE_SHIFT;
-			if (zone_size[0] < end)
-				zone_size[0] = end;
-		}
+		/*
+		 * The size of this node has already been determined.
+		 * If we need to do anything fancy with the allocation
+		 * of this memory to the zones, now is the time to do
+		 * it.  For now, we don't touch zhole_size.
+		 */
+		zone_size[0] = bdata->node_low_pfn -
+				(bdata->node_boot_start >> PAGE_SHIFT);
+
+		free_area_init_node(node, pgdat, zone_size,
+				bdata->node_boot_start, zhole_size);
 	}
-	free_area_init(zone_size);
 
 	/*
 	 * finish off the bad pages once
@@ -256,32 +431,33 @@
  */
 void __init mem_init(void)
 {
-	extern char __init_begin, __init_end, _text, _etext, _end;
+	extern char __init_begin, __init_end;
 	unsigned int codepages, datapages, initpages;
-	int i;
+	int i, node;
 
 	codepages = &_etext - &_text;
 	datapages = &_end - &_etext;
 	initpages = &__init_end - &__init_begin;
 
-	max_mapnr   = max_low_pfn;
-	high_memory = (void *)__va(PHYS_OFFSET + max_low_pfn * PAGE_SIZE);
+	high_memory = (void *)__va(meminfo.end);
+	max_mapnr   = MAP_NR(high_memory);
 
 	/*
 	 * We may have non-contiguous memory.  Setup the PageSkip stuff,
 	 * and mark the areas of mem_map which can be freed
 	 */
 	if (meminfo.nr_banks != 1)
-		create_memmap_holes();
+		create_memmap_holes(&meminfo);
 
 	/* this will put all unused low memory onto the freelists */
-	totalram_pages += free_all_bootmem();
+	for (node = 0; node < numnodes; node++)
+		totalram_pages += free_all_bootmem_node(node);
 
 	/*
 	 * Since our memory may not be contiguous, calculate the
 	 * real number of pages we have in this system
 	 */
-	printk("Memory:");
+	printk(KERN_INFO "Memory:");
 
 	num_physpages = 0;
 	for (i = 0; i < meminfo.nr_banks; i++) {
@@ -290,7 +466,8 @@
 	}
 
 	printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
-	printk("Memory: %luKB available (%dK code, %dK data, %dK init)\n",
+	printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
+		"%dK data, %dK init)\n",
 		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
 		codepages >> 10, datapages >> 10, initpages >> 10);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/map.h linux/arch/arm/mm/map.h
--- v2.3.99-pre5/linux/arch/arm/mm/map.h	Tue Nov 23 22:42:20 1999
+++ linux/arch/arm/mm/map.h	Tue Apr 25 16:54:39 2000
@@ -19,7 +19,7 @@
 extern struct map_desc	io_desc[];
 extern unsigned int	io_desc_size;
 
-extern void zonesize_init(unsigned int *);
-extern void create_memmap_holes(void);
-extern void pagetable_init(void);
+struct meminfo;
 
+extern void create_memmap_holes(struct meminfo *);
+extern void pagetable_init(struct meminfo *);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-armo.c linux/arch/arm/mm/mm-armo.c
--- v2.3.99-pre5/linux/arch/arm/mm/mm-armo.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/arm/mm/mm-armo.c	Tue Apr 25 16:54:39 2000
@@ -147,7 +147,7 @@
  * some more work to get it to fit into our separate processor and
  * architecture structure.
  */
-void __init pagetable_init(void)
+void __init pagetable_init(struct meminfo *mi)
 {
 	pte_t *pte;
 	int i;
@@ -165,6 +165,6 @@
 /*
  * We never have holes in the memmap
  */
-void __init create_memmap_holes(void)
+void __init create_memmap_holes(struct meminfo *mi)
 {
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- v2.3.99-pre5/linux/arch/arm/mm/mm-armv.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/mm/mm-armv.c	Tue Apr 25 16:54:39 2000
@@ -310,7 +310,7 @@
 	}
 }
 
-void __init pagetable_init(void)
+void __init pagetable_init(struct meminfo *mi)
 {
 	struct map_desc *init_maps, *p, *q;
 	unsigned long address = 0;
@@ -335,13 +335,13 @@
 
 	p ++;
 
-	for (i = 0; i < meminfo.nr_banks; i++) {
-		if (meminfo.bank[i].size == 0)
+	for (i = 0; i < mi->nr_banks; i++) {
+		if (mi->bank[i].size == 0)
 			continue;
 
-		p->physical   = meminfo.bank[i].start;
+		p->physical   = mi->bank[i].start;
 		p->virtual    = __phys_to_virt(p->physical);
-		p->length     = meminfo.bank[i].size;
+		p->length     = mi->bank[i].size;
 		p->domain     = DOMAIN_KERNEL;
 		p->prot_read  = 0;
 		p->prot_write = 1;
@@ -414,7 +414,7 @@
  * The mem_map array can get very big.  Mark the end of the valid mem_map
  * banks with PG_skip, and setup the address validity bitmap.
  */
-void __init create_memmap_holes(void)
+void __init create_memmap_holes(struct meminfo *mi)
 {
 	unsigned int start_pfn, end_pfn = -1;
 	struct page *pg = NULL;
@@ -423,11 +423,11 @@
 #define PFN(x)	(((x) - PHYS_OFFSET) >> PAGE_SHIFT)
 #define free_bootmem(s,sz)  free_bootmem(((s)<<PAGE_SHIFT)+PHYS_OFFSET, (sz)<<PAGE_SHIFT)
 
-	for (i = 0; i < meminfo.nr_banks; i++) {
-		if (meminfo.bank[i].size == 0)
+	for (i = 0; i < mi->nr_banks; i++) {
+		if (mi->bank[i].size == 0)
 			continue;
 
-		start_pfn = PFN(meminfo.bank[i].start);
+		start_pfn = PFN(mi->bank[i].start);
 
 		/*
 		 * subtle here - if we have a full bank, then
@@ -447,9 +447,9 @@
 			pg = NULL;
 		}
 
-		end_pfn = PFN(meminfo.bank[i].start + meminfo.bank[i].size);
+		end_pfn = PFN(mi->bank[i].start + mi->bank[i].size);
 
-		if (end_pfn != PFN(meminfo.end))
+		if (end_pfn != PFN(mi->end))
 			pg = mem_map + end_pfn;
 	}
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c
--- v2.3.99-pre5/linux/arch/arm/mm/mm-ebsa110.c	Mon Nov  1 13:56:26 1999
+++ linux/arch/arm/mm/mm-ebsa110.c	Tue Apr 25 16:54:39 2000
@@ -8,6 +8,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 
+#include <asm/hardware.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 
@@ -15,7 +16,7 @@
  
 #define SIZE(x) (sizeof(x) / sizeof(x[0]))
 
-const struct map_desc io_desc[] __initdata = {
+struct map_desc io_desc[] __initdata = {
 	{ IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
 	{ IO_BASE             , IO_START  , IO_SIZE   , DOMAIN_IO, 0, 1, 0, 0 }
 };
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c
--- v2.3.99-pre5/linux/arch/arm/mm/mm-rpc.c	Mon Nov  1 13:56:26 1999
+++ linux/arch/arm/mm/mm-rpc.c	Tue Apr 25 16:54:39 2000
@@ -18,7 +18,7 @@
 
 struct map_desc io_desc[] __initdata = {
 	/* VRAM		*/
-	{ SCREEN2_BASE,	SCREEN_START,	2*1048576, DOMAIN_IO, 0, 1, 0, 0 },
+	{ SCREEN_BASE,	SCREEN_START,	2*1048576, DOMAIN_IO, 0, 1, 0, 0 },
 	/* IO space	*/
 	{ IO_BASE,	IO_START,	IO_SIZE	 , DOMAIN_IO, 0, 1, 0, 0 },
 	/* EASI space	*/
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c
--- v2.3.99-pre5/linux/arch/arm/mm/mm-sa1100.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/mm/mm-sa1100.c	Tue Apr 25 16:54:39 2000
@@ -9,6 +9,10 @@
  * 1999/12/04 Nicolas Pitre <nico@cam.org>
  *	Converted memory definition for struct meminfo initialisations.
  *	Memory is listed physically now.
+ *
+ * 2000/04/07 Nicolas Pitre <nico@cam.org>
+ *	Reworked for real-time selection of memory definitions
+ *
  */
 
 #include <linux/config.h>
@@ -23,79 +27,109 @@
 #define SIZE(x) (sizeof(x) / sizeof(x[0]))
 
 
-/*
- * These are the RAM memory mappings for SA1100 implementations.
- * Note that LART is a special case - it doesn't use physical 
- * address line A23 on the DRAM, so we effectively have 4 * 8MB
- * in two banks.
- */
-struct mem_desc { 
-	unsigned long phys_start;
-	unsigned long length;
-} mem_desc[] __initdata = {
-#if defined(CONFIG_SA1100_BRUTUS)
-	{ 0xc0000000, 0x00400000 },	/* 4MB */
-	{ 0xc8000000, 0x00400000 },	/* 4MB */
-	{ 0xd0000000, 0x00400000 },	/* 4MB */
-	{ 0xd8000000, 0x00400000 }	/* 4MB */
-#elif defined(CONFIG_SA1100_EMPEG)
-	{ 0xc0000000, 0x00400000 },	/* 4MB */
-	{ 0xc8000000, 0x00400000 }	/* 4MB */
-#elif defined(CONFIG_SA1100_LART)
-	{ 0xc0000000, 0x00800000 },	/* 8MB */
-	{ 0xc1000000, 0x00800000 },	/* 8MB */
-	{ 0xc8000000, 0x00800000 },	/* 8MB */
-	{ 0xc9000000, 0x00800000 }	/* 8MB */
-#elif defined(CONFIG_SA1100_VICTOR)
-	{ 0xc0000000, 0x00400000 }	/* 4MB */
-#elif defined(CONFIG_SA1100_THINCLIENT)
-	{ 0xc0000000, 0x01000000 }	/* 16MB */
-#elif defined(CONFIG_SA1100_TIFON)
-	{ 0xc0000000, 0x01000000 },	/* 16MB */
-	{ 0xc8000000, 0x01000000 }	/* 16MB */
-#else
-#error missing memory configuration
+#define SA1100_STD_IO_MAPPING \
+ /* virtual     physical    length      domain     r  w  c  b */ \
+  { 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ \
+  { 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ \
+  { 0xe8000000, 0x28000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */ \
+  { 0xec000000, 0x38000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */ \
+  { 0xf0000000, 0x2c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */ \
+  { 0xf4000000, 0x3c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */ \
+  { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ \
+  { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ \
+  { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ \
+  { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }  /* LCD + DMA */
+
+
+static struct map_desc assabet_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_ASSABET
+  { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xdc000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
+  SA1100_STD_IO_MAPPING
 #endif
 };
 
-unsigned int __initdata mem_desc_size = SIZE(mem_desc);
+static struct map_desc bitsy_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_BITSY
+  { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+  SA1100_STD_IO_MAPPING
+#endif
+};
 
+static struct map_desc empeg_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_EMPEG
+  { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+  SA1100_STD_IO_MAPPING
+#endif
+};
 
-struct map_desc io_desc[] __initdata = {
-	/* virtual           physical     length     domain    r  w  c  b */
-#if defined(CONFIG_SA1100_VICTOR)
-	{ 0xd0000000,      0x00000000,  0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
-#elif defined(CONFIG_SA1100_EMPEG)
-	{ EMPEG_FLASHBASE, 0x00000000,  0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
-#elif defined(CONFIG_SA1100_THINCLIENT)
+static struct map_desc thinclient_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_THINCLIENT
 #if 1
-	/* ThinClient: only one of those... */
-//	{ 0xd0000000,      0x00000000,  0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */
-	{ 0xd0000000,      0x08000000,  0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */
+  /* ThinClient: only one of those... */
+//  { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */
+  { 0xd0000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */
 #else
-	/* GraphicsClient: */
-	{ 0xd0000000,      0x08000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
-	{ 0xd0800000,      0x18000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */
-#endif
-#elif defined(CONFIG_SA1100_TIFON)
-	{ 0xd0000000,      0x00000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
-	{ 0xd0800000,      0x08000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
-#endif
-#if defined( CONFIG_SA1101 )
-	{ 0xdc000000,      SA1101_BASE, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1101 */
-#elif defined( CONFIG_SA1100_THINCLIENT )
-	{ 0xdc000000,      0x10000000,  0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
-#endif
-	{ 0xe0000000,      0x20000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
-	{ 0xe4000000,      0x30000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
-	{ 0xe8000000,      0x28000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */
-	{ 0xec000000,      0x38000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */
-	{ 0xf0000000,      0x2c000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */
-	{ 0xf4000000,      0x3c000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */
-	{ 0xf8000000,      0x80000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
-	{ 0xfa000000,      0x90000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
-	{ 0xfc000000,      0xa0000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
-	{ 0xfe000000,      0xb0000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }  /* LCD + DMA */
+  /* GraphicsClient: */
+  { 0xd0000000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xd0800000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */
+#endif
+  { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
+  SA1100_STD_IO_MAPPING
+#endif
+};
+
+static struct map_desc tifon_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_TIFON
+  { 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
+  SA1100_STD_IO_MAPPING
+#endif
 };
 
-unsigned int __initdata io_desc_size = SIZE(io_desc);
+static struct map_desc victor_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_VICTOR
+  { 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+  SA1100_STD_IO_MAPPING
+#endif
+};
+
+
+static struct map_desc default_io_desc[] __initdata = {
+  SA1100_STD_IO_MAPPING
+};
+
+
+/*
+ * Here it would be wiser to simply assign a pointer to the appropriate 
+ * list, but io_desc is already declared as an array in "map.h".
+ */
+struct map_desc io_desc[20] __initdata = { { 0, }, };
+unsigned int io_desc_size;
+
+void __init select_sa1100_io_desc(void)
+{
+	if( machine_is_assabet() ) {
+		memcpy( io_desc, assabet_io_desc, sizeof(assabet_io_desc) );
+		io_desc_size = SIZE(assabet_io_desc);
+	} else if( machine_is_bitsy() ) {
+		memcpy( io_desc, bitsy_io_desc, sizeof(bitsy_io_desc) );
+		io_desc_size = SIZE(bitsy_io_desc);
+	} else if( machine_is_empeg() ) {
+		memcpy( io_desc, empeg_io_desc, sizeof(empeg_io_desc) );
+		io_desc_size = SIZE(empeg_io_desc);
+	} else if( machine_is_thinclient() ) {
+		memcpy( io_desc, thinclient_io_desc, sizeof(thinclient_io_desc) );
+		io_desc_size = SIZE(thinclient_io_desc);
+	} else if( machine_is_tifon() ) {
+		memcpy( io_desc, tifon_io_desc, sizeof(tifon_io_desc) );
+		io_desc_size = SIZE(tifon_io_desc);
+	} else if( machine_is_victor() ) {
+		memcpy( io_desc, victor_io_desc, sizeof(victor_io_desc) );
+		io_desc_size = SIZE(victor_io_desc);
+	} else {
+		memcpy( io_desc, default_io_desc, sizeof(default_io_desc) );
+		io_desc_size = SIZE(default_io_desc);
+	}
+}
+
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.3.99-pre5/linux/arch/arm/mm/proc-sa110.S	Tue Apr 11 15:09:12 2000
+++ linux/arch/arm/mm/proc-sa110.S	Tue Apr 25 16:54:39 2000
@@ -4,7 +4,9 @@
  * (C) 1997-2000 Russell King
  *
  * These are the low level assembler for performing cache and TLB
- * functions on the StrongARM-110 and StrongARM-1100
+ * functions on the StrongARM-110, StrongARM-1100 and StrongARM-1110.
+ * 
+ * Note that SA1100 and SA1110 share everything but their name and CPU ID.
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
@@ -420,13 +422,12 @@
 		mov	pc, lr
 
 ENTRY(cpu_sa110_proc_fin)
-ENTRY(cpu_sa1100_proc_fin)
 		stmfd	sp!, {r1, lr}
 		mrs	r0, cpsr
 		orr	r0, r0, #F_BIT | I_BIT
 		msr	cpsr, r0
 		bl	cpu_sa110_flush_cache_all	@ clean caches
-		mov	r0, #0
+1:		mov	r0, #0
 		mcr	p15, 0, r0, c15, c2, 2		@ Disable clock switching
 		mrc	p15, 0, r0, c1, c0, 0
 		bic	r0, r0, #0x1000			@ ...i............
@@ -434,8 +435,17 @@
 		mcr	p15, 0, r0, c1, c0, 0		@ disable caches
 		ldmfd	sp!, {r1, pc}
 
+ENTRY(cpu_sa1100_proc_fin)
+		stmfd	sp!, {r1, lr}
+		mrs	r0, cpsr
+		orr	r0, r0, #F_BIT | I_BIT
+		msr	cpsr, r0
+		bl	cpu_sa1100_flush_cache_all	@ clean caches
+		b	1b
+
+
 		.align	5
-idle:		mcr	p15, 0, r0, c15, c8, 2		@ Wait for interrupt
+idle:		mcr	p15, 0, r0, c15, c8, 2		@ Wait for interrupt, cache aligned
 		mov	r0, r0				@ safety
 		mov	pc, lr
 /*
@@ -483,16 +493,14 @@
 		bic	ip, ip, #0x1100			@ ...i...s........
 		mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
 		mov	pc, r0
-/*
- * Purpose : Function pointers used to access above functions - all calls
- *	     come through these
- */
+
 
 cpu_manu_name:	.asciz	"Intel"
-ENTRY(cpu_sa110_name)
-		.asciz	"StrongARM-110"
-ENTRY(cpu_sa1100_name)
+cpu_sa110_name:	.asciz	"StrongARM-110"
+cpu_sa1100_name:
 		.asciz	"StrongARM-1100"
+cpu_sa1110_name:
+		.asciz	"StrongARM-1110"
 		.align
 
 		.section ".text.init", #alloc, #execinstr
@@ -511,6 +519,13 @@
 		orr	r0, r0, #0x1100			@ ...I...S........
 		mov	pc, lr
 
+		.text
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ *	     come through these
+ */
+
 		.type	sa110_processor_functions, #object
 ENTRY(sa110_processor_functions)
 		.word	cpu_sa110_data_abort
@@ -543,6 +558,9 @@
 		.size	cpu_sa110_info, . - cpu_sa110_info
 
 
+/*
+ * SA1100 and SA1110 share the same function calls
+ */
 		.type	sa1100_processor_functions, #object
 ENTRY(sa1100_processor_functions)
 		.word	cpu_sa1100_data_abort
@@ -573,6 +591,12 @@
 		.long	cpu_sa1100_name
 		.size	cpu_sa1100_info, . - cpu_sa1100_info
 
+cpu_sa1110_info:
+		.long	cpu_manu_name
+		.long	cpu_sa1110_name
+		.size	cpu_sa1110_info, . - cpu_sa1110_info
+
+
 		.type	cpu_arch_name, #object
 cpu_arch_name:	.asciz	"armv4"
 		.size	cpu_arch_name, . - cpu_arch_name
@@ -609,5 +633,18 @@
 		.long	cpu_sa1100_info
 		.long	sa1100_processor_functions
 		.size	__sa1100_proc_info, . - __sa1100_proc_info
+
+		.type	__sa1110_proc_info,#object
+__sa1110_proc_info:
+		.long	0x6901b110
+		.long	0xfffffff0
+		.long	0x00000c02
+		b	__sa110_setup
+		.long	cpu_arch_name
+		.long	cpu_elf_name
+		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+		.long	cpu_sa1110_info
+		.long	sa1100_processor_functions
+		.size	__sa1110_proc_info, . - __sa1110_proc_info
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.99-pre5/linux/arch/i386/config.in	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/config.in	Mon Apr 24 13:39:34 2000
@@ -20,48 +20,54 @@
 choice 'Processor family' \
 	"386			CONFIG_M386	\
 	 486/Cx486		CONFIG_M486	\
-	 586/K5/5x86/6x86	CONFIG_M586	\
+	 586/K5/5x86/6x86/6x86MX	CONFIG_M586	\
 	 Pentium/TSC		CONFIG_M586TSC	\
-	 PPro/6x86MX		CONFIG_M686 \
+	 PPro			CONFIG_M686 \
 	 K6/II/III		CONFIG_MK6 \
 	 Athlon                 CONFIG_MK7" PPro
 #
 # Define implied options from the CPU selection here
 #
-if [ "$CONFIG_M386" != "y" ]; then
+if [ "$CONFIG_M386" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_BYTES 16
+else
    define_bool CONFIG_X86_WP_WORKS_OK y
    define_bool CONFIG_X86_INVLPG y
    define_bool CONFIG_X86_CMPXCHG y
    define_bool CONFIG_X86_BSWAP y
    define_bool CONFIG_X86_POPAD_OK y
 fi
-if [ "$CONFIG_M386" = "y" -o "$CONFIG_M486" = "y" ]; then
-   define_int CONFIG_X86_L1_CACHE_BYTES 16
-else
-   define_int CONFIG_X86_L1_CACHE_BYTES 32
-fi
-if [ "$CONFIG_M486" = "y" -o "$CONFIG_M586" = "y" ]; then
+if [ "$CONFIG_M486" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_BYTES 16
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
 fi
-if [ "$CONFIG_M586TSC" = "y" ]; then
+if [ "$CONFIG_M586" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_BYTES 32
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_TSC y
 fi
-if [ "$CONFIG_MK6" = "y" ]; then
+if [ "$CONFIG_M586TSC" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_BYTES 32
+   define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
-   define_bool CONFIG_X86_USE_3DNOW y
-   define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_M686" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_BYTES 32
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
+if [ "$CONFIG_MK6" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_BYTES 32
+   define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+fi
 if [ "$CONFIG_MK7" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_BYTES 64
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_USE_3DNOW y
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.99-pre5/linux/arch/i386/defconfig	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/defconfig	Mon Apr 24 15:53:19 2000
@@ -107,6 +107,7 @@
 #
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_STRIPED is not set
@@ -189,8 +190,8 @@
 # CONFIG_IDEDMA_PCI_EXPERIMENTAL is not set
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
@@ -214,6 +215,7 @@
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_VIA82CXXX_TUNING is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 CONFIG_BLK_DEV_IDE_MODES=y
@@ -385,7 +387,10 @@
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_IBMTR is not set
-# CONFIG_PCMCIA_3C575 is not set
+
+#
+#   3Com 3c575 moved to Ethernet 10/100 menu
+#
 # CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_NET_PCMCIA_RADIO=y
 CONFIG_PCMCIA_RAYCS=y
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c
--- v2.3.99-pre5/linux/arch/i386/kernel/acpi.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/kernel/acpi.c	Mon Apr 24 18:17:52 2000
@@ -583,6 +583,8 @@
 			dt = acpi_map_table(facp->dsdt);
 			if (acpi_init_table(&acpi_dsdt, dt, 1))
 				acpi_unmap_table(dt);
+
+			break;
 		}
 		else {
 			acpi_unmap_table(dt);
@@ -1127,6 +1129,7 @@
 	// finished sleeping, update system time
 	acpi_update_clock();
 	acpi_enter_dx(ACPI_D0);
+	acpi_sleep_state = ACPI_S0;
 	
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
--- v2.3.99-pre5/linux/arch/i386/kernel/apic.c	Sat Feb 12 11:22:10 2000
+++ linux/arch/i386/kernel/apic.c	Wed Apr 12 09:33:19 2000
@@ -4,7 +4,9 @@
  *	(c) 1999, 2000 Ingo Molnar <mingo@redhat.com>
  *
  *	Fixes
- *	Maciej W. Rozycki	:	Bits for genuine 82489DX timers
+ *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs;
+ *					thanks to Eric Gilmore for
+ *					testing these extensively
  */
 
 #include <linux/config.h>
@@ -44,32 +46,96 @@
 	return maxlvt;
 }
 
-void disable_local_APIC (void)
+static void clear_local_APIC(void)
 {
-	unsigned long value;
-        int maxlvt;
+	int maxlvt;
+	unsigned long v;
+
+	maxlvt = get_maxlvt();
 
 	/*
-	 * Disable APIC
+	 * Careful: we have to set masks only first to deassert
+	 * any level-triggered sources.
 	 */
- 	value = apic_read(APIC_SPIV);
- 	value &= ~(1<<8);
- 	apic_write(APIC_SPIV,value);
+	v = apic_read(APIC_LVTT);
+	apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+	v = apic_read(APIC_LVT0);
+	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
+	v = apic_read(APIC_LVT1);
+	apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
+	if (maxlvt >= 3) {
+		v = apic_read(APIC_LVTERR);
+		apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
+	}
+	if (maxlvt >= 4) {
+		v = apic_read(APIC_LVTPC);
+		apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
+	}
 
 	/*
 	 * Clean APIC state for other OSs:
 	 */
- 	value = apic_read(APIC_SPIV);
- 	value &= ~(1<<8);
- 	apic_write(APIC_SPIV,value);
-	maxlvt = get_maxlvt();
-	apic_write_around(APIC_LVTT, 0x00010000);
-	apic_write_around(APIC_LVT0, 0x00010000);
-	apic_write_around(APIC_LVT1, 0x00010000);
+	apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
+	apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+	apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
 	if (maxlvt >= 3)
-		apic_write_around(APIC_LVTERR, 0x00010000);
+		apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
 	if (maxlvt >= 4)
-		apic_write_around(APIC_LVTPC, 0x00010000);
+		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
+}
+
+void __init connect_bsp_APIC(void)
+{
+	if (pic_mode) {
+		/*
+		 * Do not trust the local APIC being empty at bootup.
+		 */
+		clear_local_APIC();
+		/*
+		 * PIC mode, enable symmetric IO mode in the IMCR,
+		 * i.e. connect BSP's local APIC to INT and NMI lines.
+		 */
+		printk("leaving PIC mode, enabling symmetric IO mode.\n");
+		outb(0x70, 0x22);
+		outb(0x01, 0x23);
+	}
+}
+
+void disconnect_bsp_APIC(void)
+{
+	if (pic_mode) {
+		/*
+		 * Put the board back into PIC mode (has an effect
+		 * only on certain older boards).  Note that APIC
+		 * interrupts, including IPIs, won't work beyond
+		 * this point!  The only exception are INIT IPIs.
+		 */
+		printk("disabling symmetric IO mode, entering PIC mode.\n");
+		outb(0x70, 0x22);
+		outb(0x00, 0x23);
+	}
+}
+
+void disable_local_APIC(void)
+{
+	unsigned long value;
+
+	clear_local_APIC();
+
+	/*
+	 * Disable APIC (implies clearing of registers
+	 * for 82489DX!).
+	 */
+	value = apic_read(APIC_SPIV);
+	value &= ~(1<<8);
+	apic_write_around(APIC_SPIV, value);
+}
+
+void __init sync_Arb_IDs(void)
+{
+	Dprintk("Synchronizing Arb IDs.\n");
+	apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
+				| APIC_DM_INIT);
 }
 
 extern void __error_in_apic_c (void);
@@ -78,6 +144,9 @@
 {
 	unsigned long value, ver, maxlvt;
 
+	value = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(value);
+
 	if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f)
 		__error_in_apic_c();
 
@@ -87,11 +156,12 @@
 	if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
 		BUG();
 
- 	value = apic_read(APIC_SPIV);
+	value = apic_read(APIC_SPIV);
+	value &= ~APIC_VECTOR_MASK;
 	/*
 	 * Enable APIC
 	 */
- 	value |= (1<<8);
+	value |= (1<<8);
 
 	/*
 	 * Some unknown Intel IO/APIC (or APIC) errata is biting us with
@@ -108,7 +178,7 @@
 	 */
 #if 0
 	/* Enable focus processor (bit==0) */
- 	value &= ~(1<<9);
+	value &= ~(1<<9);
 #else
 	/* Disable focus processor (bit==1) */
 	value |= (1<<9);
@@ -117,7 +187,7 @@
 	 * Set spurious IRQ vector
 	 */
 	value |= SPURIOUS_APIC_VECTOR;
- 	apic_write(APIC_SPIV,value);
+	apic_write_around(APIC_SPIV, value);
 
 	/*
 	 * Set up LVT0, LVT1:
@@ -126,48 +196,44 @@
 	 * strictly necessery in pure symmetric-IO mode, but sometimes
 	 * we delegate interrupts to the 8259A.
 	 */
-	if (!smp_processor_id()) {
-		value = 0x00000700;
+	/*
+	 * TODO: set up through-local-APIC from through-I/O-APIC? --macro
+	 */
+	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
+	if (!smp_processor_id() && (pic_mode || !value)) {
+		value = APIC_DM_EXTINT;
 		printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
 	} else {
-		value = 0x00010700;
+		value = APIC_DM_EXTINT | APIC_LVT_MASKED;
 		printk("masked ExtINT on CPU#%d\n", smp_processor_id());
 	}
- 	apic_write_around(APIC_LVT0,value);
+	apic_write_around(APIC_LVT0, value);
 
 	/*
 	 * only the BP should see the LINT1 NMI signal, obviously.
 	 */
 	if (!smp_processor_id())
-		value = 0x00000400;		// unmask NMI
+		value = APIC_DM_NMI;
 	else
-		value = 0x00010400;		// mask NMI
- 	apic_write_around(APIC_LVT1,value);
+		value = APIC_DM_NMI | APIC_LVT_MASKED;
+	if (!APIC_INTEGRATED(ver))		/* 82489DX */
+		value |= APIC_LVT_LEVEL_TRIGGER;
+	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
+		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */
 			apic_write(APIC_ESR, 0);
-		}
 		value = apic_read(APIC_ESR);
 		printk("ESR value before enabling vector: %08lx\n", value);
 
-		value = apic_read(APIC_LVTERR);
 		value = ERROR_APIC_VECTOR;      // enables sending errors
-		apic_write(APIC_LVTERR,value);
+		apic_write_around(APIC_LVTERR, value);
 		/*
 		 * spec says clear errors after enabling vector.
 		 */
-		if (maxlvt != 3) {
-			apic_readaround(APIC_SPIV);
+		if (maxlvt > 3)
 			apic_write(APIC_ESR, 0);
-		}
 		value = apic_read(APIC_ESR);
 		printk("ESR value after enabling vector: %08lx\n", value);
 	} else
@@ -177,22 +243,23 @@
 	 * 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);
+	value = apic_read(APIC_TASKPRI);
+	value &= ~APIC_TPRI_MASK;
+	apic_write_around(APIC_TASKPRI, value);
 
 	/*
 	 * Set up the logical destination ID and put the
 	 * APIC into flat delivery mode.
 	 */
- 	value = apic_read(APIC_LDR);
+	value = apic_read(APIC_LDR);
 	value &= ~APIC_LDR_MASK;
 	value |= (1<<(smp_processor_id()+24));
- 	apic_write(APIC_LDR,value);
+	apic_write_around(APIC_LDR, value);
 
- 	value = apic_read(APIC_DFR);
-	value |= SET_APIC_DFR(0xf);
- 	apic_write(APIC_DFR, value);
+	/*
+	 * Must be "all ones" explicitly for 82489DX.
+	 */
+	apic_write_around(APIC_DFR, 0xffffffff);
 }
 
 void __init init_apic_mappings(void)
@@ -214,6 +281,13 @@
 	set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
 	Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
 
+	/*
+	 * Fetch the APIC ID of the BSP in case we have a
+	 * default configuration (or the MP table is broken).
+	 */
+	if (boot_cpu_id == -1U)
+		boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+
 #ifdef CONFIG_X86_IO_APIC
 	{
 		unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
@@ -285,7 +359,7 @@
 	 * chipset timer can cause.
 	 */
 
-	} while (delta<300);
+	} while (delta < 300);
 }
 
 /*
@@ -305,21 +379,19 @@
 {
 	unsigned int lvtt1_value, tmp_value;
 
-	tmp_value = apic_read(APIC_LVTT);
 	lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
 			APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-	apic_write(APIC_LVTT, lvtt1_value);
+	apic_write_around(APIC_LVTT, lvtt1_value);
 
 	/*
 	 * Divide PICLK by 16
 	 */
 	tmp_value = apic_read(APIC_TDCR);
-	apic_write(APIC_TDCR, (tmp_value
+	apic_write_around(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);
+	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
 void setup_APIC_timer(void * data)
@@ -353,6 +425,12 @@
 
 	t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
 	do {
+		/*
+		 * It looks like the 82489DX cannot handle
+		 * consecutive reads of the TMCCT register well;
+		 * this dummy read prevents it from a lockup.
+		 */
+		apic_read(APIC_SPIV);
 		t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
 		delta = (int)(t0 - t1 - slice*(smp_processor_id()+1));
 	} while (delta < 0);
@@ -490,6 +568,41 @@
 
 #undef APIC_DIVISOR
 
+#ifdef CONFIG_SMP
+static inline void handle_smp_time (int user, int cpu)
+{
+	int system = !user;
+	struct task_struct * p = current;
+	/*
+	 * 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);
+}
+#endif
+
 /*
  * Local timer interrupt handler. It does both profiling and
  * process statistics/rescheduling.
@@ -502,7 +615,6 @@
 
 inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
-	int user = (user_mode(regs) != 0);
 	int cpu = smp_processor_id();
 
 	/*
@@ -511,13 +623,8 @@
 	 * 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
@@ -532,33 +639,9 @@
 			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);
+#ifdef CONFIG_SMP
+		handle_smp_time(user_mode(regs), cpu);
+#endif
 	}
 
 	/*
@@ -603,7 +686,17 @@
  */
 asmlinkage void smp_spurious_interrupt(void)
 {
-	ack_APIC_irq();
+	unsigned long v;
+
+	/*
+	 * Check if this really is a spurious interrupt and ACK it
+	 * if it is a vectored one.  Just in case...
+	 * Spurious interrupts should not be ACKed.
+	 */
+	v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
+	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
+		ack_APIC_irq();
+
 	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
 	printk("spurious APIC interrupt on CPU#%d, should never happen.\n",
 			smp_processor_id());
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.3.99-pre5/linux/arch/i386/kernel/entry.S	Mon Mar 27 08:08:21 2000
+++ linux/arch/i386/kernel/entry.S	Mon Apr 24 13:39:34 2000
@@ -40,6 +40,7 @@
  * "current" is in register %ebx during any slow entries.
  */
 
+#include <linux/config.h>
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
@@ -201,7 +202,7 @@
 	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
 	movl %eax,EAX(%esp)		# save the return value
 ENTRY(ret_from_sys_call)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	movl processor(%ebx),%eax
 	shll $5,%eax
 	movl SYMBOL_NAME(softirq_state)(,%eax),%ecx
@@ -256,7 +257,7 @@
 
 	ALIGN
 ret_from_exception:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	GET_CURRENT(%ebx)
 	movl processor(%ebx),%eax
 	shll $5,%eax
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.3.99-pre5/linux/arch/i386/kernel/head.S	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/kernel/head.S	Mon Apr 24 13:39:34 2000
@@ -51,7 +51,7 @@
 	movl %eax,%es
 	movl %eax,%fs
 	movl %eax,%gs
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	orw %bx,%bx
 	jz 1f
 /*
@@ -105,14 +105,14 @@
 	/* Set up the stack pointer */
 	lss stack_start,%esp
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	orw  %bx,%bx
 	jz  1f				/* Initial CPU cleans BSS */
 	pushl $0
 	popfl
 	jmp checkCPUtype
 1:
-#endif __SMP__
+#endif CONFIG_SMP
 /*
  * Clear BSS first so that there are no surprises...
  */
@@ -159,7 +159,7 @@
 	rep
 	movsl
 1:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 checkCPUtype:
 #endif
 
@@ -234,7 +234,7 @@
 	orl $2,%eax		# set MP
 2:	movl %eax,%cr0
 	call check_x87
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	incb ready
 #endif
 	lgdt gdt_descr
@@ -245,7 +245,7 @@
 	movl %eax,%es
 	movl %eax,%fs
 	movl %eax,%gs
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	movl $(__KERNEL_DS), %eax
 	movl %eax,%ss		# Reload the stack pointer (segment only)
 #else
@@ -254,7 +254,7 @@
 	xorl %eax,%eax
 	lldt %ax
 	cld			# gcc2 wants the direction flag cleared at all times
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	movb ready, %cl	
 	cmpb $1,%cl
 	je 1f			# the first CPU calls start_kernel
@@ -268,7 +268,7 @@
 	jmp L6			# main should never return here, but
 				# just in case, we know what happens.
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 ready:	.byte 0
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.3.99-pre5/linux/arch/i386/kernel/i386_ksyms.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/i386/kernel/i386_ksyms.c	Fri Apr 21 16:27:21 2000
@@ -27,6 +27,11 @@
 extern int dump_fpu(elf_fpregset_t *);
 extern spinlock_t rtc_lock;
 
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+extern void machine_real_restart(unsigned char *, int);
+EXPORT_SYMBOL(machine_real_restart);
+#endif
+
 #ifdef CONFIG_SMP
 extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
 extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
@@ -68,7 +73,6 @@
 EXPORT_SYMBOL_NOVERS(__down_read_failed);
 EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 /* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy);
 EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
 EXPORT_SYMBOL(__udelay);
@@ -84,7 +88,6 @@
 
 EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strstr);
 
 EXPORT_SYMBOL(strncpy_from_user);
 EXPORT_SYMBOL(__strncpy_from_user);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c
--- v2.3.99-pre5/linux/arch/i386/kernel/i8259.c	Mon Mar 27 08:08:21 2000
+++ linux/arch/i386/kernel/i8259.c	Wed Apr 12 09:33:19 2000
@@ -415,7 +415,7 @@
 	for (i = 0; i < NR_IRQS; i++) {
 		irq_desc[i].status = IRQ_DISABLED;
 		irq_desc[i].action = 0;
-		irq_desc[i].depth = 0;
+		irq_desc[i].depth = 1;
 
 		if (i < 16) {
 			/*
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.3.99-pre5/linux/arch/i386/kernel/io_apic.c	Mon Mar 27 08:08:21 2000
+++ linux/arch/i386/kernel/io_apic.c	Wed Apr 12 09:33:19 2000
@@ -13,7 +13,9 @@
  *	and Ingo Molnar <mingo@redhat.com>
  *
  *	Fixes
- *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs
+ *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs;
+ *					thanks to Eric Gilmore for
+ *					testing these extensively
  */
 
 #include <linux/mm.h>
@@ -46,9 +48,6 @@
 /* MP IRQ source entries */
 int mp_irq_entries = 0;
 
-/* non-0 if default (table-less) MP configuration */
-int mpc_default_type = 0;
-
 /*
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
@@ -166,7 +165,7 @@
 
 #define MAX_PIRQS 8
 int pirq_entries [MAX_PIRQS];
-int pirqs_enabled;
+int pirqs_enabled = 0;
 int skip_ioapic_setup = 0;
 
 static int __init ioapic_setup(char *str)
@@ -235,7 +234,8 @@
 		int lbus = mp_irqs[i].mpc_srcbus;
 
 		if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
-		     mp_bus_id_to_type[lbus] == MP_BUS_EISA) &&
+		     mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
+		     mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&
 		    (mp_irqs[i].mpc_irqtype == type) &&
 		    (mp_irqs[i].mpc_srcbusirq == 0x00))
 
@@ -260,13 +260,15 @@
 			if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
 				break;
 
-		if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
-		    (mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
+		if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
 		    !mp_irqs[i].mpc_irqtype &&
 		    (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) &&
 		    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
 			int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
 
+			if (!(apic || IO_APIC_IRQ(irq)))
+				continue;
+
 			if (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))
 				return irq;
 			/*
@@ -298,15 +300,27 @@
  * EISA conforming in the MP table, that means its trigger type must
  * be read in from the ELCR */
 
-#define default_EISA_trigger(idx)	(EISA_ELCR(mp_irqs[idx].mpc_dstirq))
+#define default_EISA_trigger(idx)	(EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))
 #define default_EISA_polarity(idx)	(0)
 
-/* ISA interrupts are always polarity zero edge triggered, even when
- * listed as conforming in the MP table. */
+/* ISA interrupts are always polarity zero edge triggered,
+ * when listed as conforming in the MP table. */
 
 #define default_ISA_trigger(idx)	(0)
 #define default_ISA_polarity(idx)	(0)
 
+/* PCI interrupts are always polarity one level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_PCI_trigger(idx)	(1)
+#define default_PCI_polarity(idx)	(1)
+
+/* MCA interrupts are always polarity zero level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_MCA_trigger(idx)	(1)
+#define default_MCA_polarity(idx)	(0)
+
 static int __init MPBIOS_polarity(int idx)
 {
 	int bus = mp_irqs[idx].mpc_srcbus;
@@ -326,14 +340,19 @@
 					polarity = default_ISA_polarity(idx);
 					break;
 				}
-				case MP_BUS_EISA:
+				case MP_BUS_EISA: /* EISA pin */
 				{
 					polarity = default_EISA_polarity(idx);
 					break;
 				}
 				case MP_BUS_PCI: /* PCI pin */
 				{
-					polarity = 1;
+					polarity = default_PCI_polarity(idx);
+					break;
+				}
+				case MP_BUS_MCA: /* MCA pin */
+				{
+					polarity = default_MCA_polarity(idx);
 					break;
 				}
 				default:
@@ -385,19 +404,24 @@
 		{
 			switch (mp_bus_id_to_type[bus])
 			{
-				case MP_BUS_ISA:
+				case MP_BUS_ISA: /* ISA pin */
 				{
 					trigger = default_ISA_trigger(idx);
 					break;
 				}
-				case MP_BUS_EISA:
+				case MP_BUS_EISA: /* EISA pin */
 				{
 					trigger = default_EISA_trigger(idx);
 					break;
 				}
-				case MP_BUS_PCI: /* PCI pin, level */
+				case MP_BUS_PCI: /* PCI pin */
 				{
-					trigger = 1;
+					trigger = default_PCI_trigger(idx);
+					break;
+				}
+				case MP_BUS_MCA: /* MCA pin */
+				{
+					trigger = default_MCA_trigger(idx);
 					break;
 				}
 				default:
@@ -460,6 +484,7 @@
 	{
 		case MP_BUS_ISA: /* ISA pin */
 		case MP_BUS_EISA:
+		case MP_BUS_MCA:
 		{
 			irq = mp_irqs[idx].mpc_srcbusirq;
 			break;
@@ -624,8 +649,8 @@
 
 	disable_8259A_irq(0);
 
-	apic_readaround(APIC_LVT0);
-	apic_write(APIC_LVT0, 0x00010700);	// mask LVT0
+	/* mask LVT0 */
+	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
 
 	init_8259A(1);
 
@@ -650,8 +675,8 @@
 	/*
 	 * 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));
+	io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
 
 	enable_8259A_irq(0);
 }
@@ -725,8 +750,8 @@
 
 	printk(KERN_DEBUG ".... IRQ redirection table:\n");
 
-	printk(KERN_DEBUG " NR Log Phy ");
-	printk(KERN_DEBUG "Mask Trig IRR Pol Stat Dest Deli Vect:   \n");
+	printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
+			  " Stat Dest Deli Vect:   \n");
 
 	for (i = 0; i <= reg_01.entries; i++) {
 		struct IO_APIC_route_entry entry;
@@ -831,13 +856,8 @@
 	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
+		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */
 			apic_write(APIC_ESR, 0);
-		}
 		v = apic_read(APIC_ESR);
 		printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
 	}
@@ -879,6 +899,32 @@
 	print_local_APIC(NULL);
 }
 
+void /*__init*/ print_PIC(void)
+{
+	unsigned int v, flags;
+
+	printk(KERN_DEBUG "\nprinting PIC contents\n");
+
+	v = inb(0xa1) << 8 | inb(0x21);
+	printk(KERN_DEBUG "... PIC  IMR: %04x\n", v);
+
+	v = inb(0xa0) << 8 | inb(0x20);
+	printk(KERN_DEBUG "... PIC  IRR: %04x\n", v);
+
+	__save_flags(flags);
+	__cli();
+	outb(0x0b,0xa0);
+	outb(0x0b,0x20);
+	v = inb(0xa0) << 8 | inb(0x20);
+	outb(0x0a,0xa0);
+	outb(0x0a,0x20);
+	__restore_flags(flags);
+	printk(KERN_DEBUG "... PIC  ISR: %04x\n", v);
+
+	v = inb(0x4d1) << 8 | inb(0x4d0);
+	printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
+}
+
 static void __init enable_IO_APIC(void)
 {
 	struct IO_APIC_reg_01 reg_01;
@@ -890,16 +936,7 @@
 	}
 	if (!pirqs_enabled)
 		for (i = 0; i < MAX_PIRQS; i++)
-			pirq_entries[i] =- 1;
-
-	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);
-	}
+			pirq_entries[i] = -1;
 
 	/*
 	 * The number of IO-APIC IRQ registers (== #pins):
@@ -925,15 +962,7 @@
 	 */
 	clear_IO_APIC();
 
-	/*
-	 * Put it back into PIC mode (has an effect only on
-	 * certain older boards)
-	 */
-	if (pic_mode) {
-		printk("disabling symmetric IO mode, entering PIC mode.\n");
-		outb_p(0x70, 0x22);
-		outb_p(0x00, 0x23);
-	}
+	disconnect_bsp_APIC();
 }
 
 /*
@@ -986,48 +1015,6 @@
 	}
 }
 
-static void __init construct_default_ISA_mptable(void)
-{
-	int i, pos = 0;
-	const int bus_type = (mpc_default_type == 2 || mpc_default_type == 3 ||
-			      mpc_default_type == 6) ? MP_BUS_EISA : MP_BUS_ISA;
-
-	for (i = 0; i < 16; i++) {
-		if (!IO_APIC_IRQ(i))
-			continue;
-
-		mp_irqs[pos].mpc_irqtype = mp_INT;
-		mp_irqs[pos].mpc_irqflag = 0;		/* default */
-		mp_irqs[pos].mpc_srcbus = 0;
-		mp_irqs[pos].mpc_srcbusirq = i;
-		mp_irqs[pos].mpc_dstapic = 0;
-		mp_irqs[pos].mpc_dstirq = i;
-		pos++;
-	}
-	mp_irq_entries = pos;
-	mp_bus_id_to_type[0] = bus_type;
-
-	/*
-	 * 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:
-		/*
-		 * pin 2 is IRQ0:
-		 */
-			mp_irqs[0].mpc_dstirq = 2;
-	}
-
-}
-
 /*
  * There is a nasty bug in some older SMP boards, their mptable lies
  * about the timer IRQ. We do the following to work around the situation:
@@ -1041,9 +1028,17 @@
 	unsigned int t1 = jiffies;
 
 	sti();
-	mdelay(40);
+	/* Let ten ticks pass... */
+	mdelay((10 * 1000) / HZ);
 
-	if (jiffies-t1>1)
+	/*
+	 * Expect a few ticks at least, to be sure some possible
+	 * glue logic does not lock up after one or two first
+	 * ticks in a non-ExtINT mode.  Also the local APIC
+	 * might have cached one ExtINT interrupt.  Finally, at
+	 * least one tick may be lost due to delays.
+	 */
+	if (jiffies - t1 > 4)
 		return 1;
 
 	return 0;
@@ -1257,8 +1252,14 @@
 
 static void enable_NMI_through_LVT0 (void * dummy)
 {
-	apic_readaround(APIC_LVT0);
-	apic_write(APIC_LVT0, 0x00000400);	// unmask and set to NMI
+	unsigned int v, ver;
+
+	ver = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(ver);
+	v = APIC_DM_NMI;			/* unmask and set to NMI */
+	if (!APIC_INTEGRATED(ver))		/* 82489DX */
+		v |= APIC_LVT_LEVEL_TRIGGER;
+	apic_write_around(APIC_LVT0, v);
 }
 
 static void setup_nmi (void)
@@ -1303,24 +1304,23 @@
 
 	printk(KERN_INFO "..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2);
 
-	/*
-	 * 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(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
+		/*
+		 * Ok, does IRQ0 through the IOAPIC work?
+		 */
+		unmask_IO_APIC_irq(0);
+		if (timer_irq_works()) {
+			if (nmi_watchdog) {
+				disable_8259A_irq(0);
+				init_8259A(1);
+				setup_nmi();
+				enable_8259A_irq(0);
+				nmi_irq_works();
+			}
+			return;
+		}
 		clear_IO_APIC_pin(0, pin1);
+		printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
 	}
 
 	printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
@@ -1334,10 +1334,9 @@
 			printk("works.\n");
 			if (nmi_watchdog) {
 				setup_nmi();
-				if (nmi_irq_works())
-					return;
-			} else
-				return;
+				nmi_irq_works();
+			}
+			return;
 		}
 		/*
 		 * Cleanup, just in case ...
@@ -1355,9 +1354,8 @@
 
 	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
+	init_8259A(1);						/* AEOI mode */
+	apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);	/* Fixed mode */
 	enable_8259A_irq(0);
 
 	if (timer_irq_works()) {
@@ -1392,20 +1390,11 @@
 	printk("ENABLING IO-APIC IRQs\n");
 
 	/*
-	 * If there are no explicit MP IRQ entries, it's either one of the
-	 * default configuration types or we are broken. In both cases it's
-	 * fine to set up most of the low 16 IO-APIC pins to ISA defaults.
-	 */
-	if (!mp_irq_entries) {
-		printk("no explicit IRQ entries, using default mptable\n");
-		construct_default_ISA_mptable();
-	}
-
-	/*
 	 * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
 	 * mptable:
 	 */
 	setup_ioapic_ids_from_mpc();
+	sync_Arb_IDs();
 	setup_IO_APIC_irqs();
 	init_IO_APIC_traps();
 	check_timer();
@@ -1421,6 +1410,7 @@
 {
 	if (!smp_found_config)
 		return;
+	connect_bsp_APIC();
 	setup_local_APIC();
 	setup_IO_APIC();
 	setup_APIC_clocks();
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.99-pre5/linux/arch/i386/kernel/irq.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/kernel/irq.c	Wed Apr 12 09:38:52 2000
@@ -462,8 +462,8 @@
  *	@irq: Interrupt to disable
  *
  *	Disable the selected interrupt line. Disables of an interrupt
- *	stack. Unlike disable_irq, this function does not ensure existing
- *	instances of the irq handler have completed before returning.
+ *	stack. Unlike disable_irq(), this function does not ensure existing
+ *	instances of the IRQ handler have completed before returning.
  *
  *	This function may be called from IRQ context.
  */
@@ -1127,7 +1127,7 @@
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
 	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
 
 	entry->nlink = 1;
 	entry->data = (void *)(long)irq;
@@ -1148,7 +1148,7 @@
 	root_irq_dir = proc_mkdir("irq", 0);
 
 	/* create /proc/irq/prof_cpu_mask */
-	entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
 
 	entry->nlink = 1;
 	entry->data = (void *)&prof_cpu_mask;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.3.99-pre5/linux/arch/i386/kernel/mca.c	Tue Mar 14 19:10:39 2000
+++ linux/arch/i386/kernel/mca.c	Wed Apr 12 09:38:52 2000
@@ -366,12 +366,12 @@
 /**
  *	mca_find_adapter - scan for adapters
  *	@id:	MCA identification to search for
- *	@start:	Starting slot
+ *	@start:	starting slot
  *
  *	Search the MCA configuration for adapters matching the 16bit
  *	ID given. The first time it should be called with start as zero
  *	and then further calls made passing the return value of the
- *	previous call until MCA_NOTFOUND is returned.
+ *	previous call until %MCA_NOTFOUND is returned.
  *
  *	Disabled adapters are not reported.
  */
@@ -411,12 +411,12 @@
 /**
  *	mca_find_unused_adapter - scan for unused adapters
  *	@id:	MCA identification to search for
- *	@start:	Starting slot
+ *	@start:	starting slot
  *
  *	Search the MCA configuration for adapters matching the 16bit
  *	ID given. The first time it should be called with start as zero
  *	and then further calls made passing the return value of the
- *	previous call until MCA_NOTFOUND is returned.
+ *	previous call until %MCA_NOTFOUND is returned.
  *
  *	Adapters that have been claimed by drivers and those that
  *	are disabled are not reported. This function thus allows a driver
@@ -647,10 +647,10 @@
  *	function is called with the buffer, slot, and device pointer (or
  *	some equally informative context information, or nothing, if you
  *	prefer), and is expected to put useful information into the
- *	buffer.  The adapter name, id, and POS registers get printed
+ *	buffer.  The adapter name, ID, and POS registers get printed
  * 	before this is called though, so don't do it again.
  *
- *	This should be called with a NULL procfn when a module
+ *	This should be called with a %NULL @procfn when a module
  *	unregisters, thus preventing kernel crashes and other such
  *	nastiness.
  */
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c
--- v2.3.99-pre5/linux/arch/i386/kernel/mpparse.c	Sat Feb 26 22:31:39 2000
+++ linux/arch/i386/kernel/mpparse.c	Wed Apr 12 09:33:19 2000
@@ -9,7 +9,7 @@
  *		Erich Boleyn	:	MP v1.4 and additional changes.
  *		Alan Cox	:	Added EBDA scanning
  *		Ingo Molnar	:	various cleanups and rewrites
- *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs
+ *	Maciej W. Rozycki	:	Bits for default MP configurations
  */
 
 #include <linux/mm.h>
@@ -34,7 +34,7 @@
  * Various Linux-internal data structures created from the
  * MP-table.
  */
-int apic_version [NR_CPUS];
+int apic_version [MAX_APICS];
 int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
 int mp_current_pci_id = 0;
@@ -42,9 +42,9 @@
 unsigned long mp_lapic_addr = 0;
 
 /* Processor that is doing the boot up */
-unsigned int boot_cpu_id = 0;
+unsigned int boot_cpu_id = -1U;
 /* Internal processor count */
-static unsigned int num_processors = 1;
+static unsigned int num_processors = 0;
 
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map = 0;
@@ -132,13 +132,12 @@
 	if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
 		Dprintk("    Bootup CPU\n");
 		boot_cpu_id = m->mpc_apicid;
-	} else
-		/* Boot CPU already counted */
-		num_processors++;
+	}
+	num_processors++;
 
-	if (m->mpc_apicid > NR_CPUS) {
-		printk("Processor #%d unused. (Max %d processors).\n",
-			m->mpc_apicid, NR_CPUS);
+	if (m->mpc_apicid > MAX_APICS) {
+		printk("Processor #%d INVALID. (Max ID: %d).\n",
+			m->mpc_apicid, MAX_APICS);
 		return;
 	}
 	ver = m->mpc_apicver;
@@ -164,18 +163,18 @@
 
 	if (strncmp(str, "ISA", 3) == 0) {
 		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
-	} else {
-	if (strncmp(str, "EISA", 4) == 0) {
+	} 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) {
+	} 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 if (strncmp(str, "MCA", 3) == 0) {
+		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
 	} 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)
@@ -197,12 +196,22 @@
 static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
 {
 	mp_irqs [mp_irq_entries] = *m;
+	Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
+		" IRQ %02x, APIC ID %x, APIC INT %02x\n",
+			m->mpc_irqtype, m->mpc_irqflag & 3,
+			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
+			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
 	if (++mp_irq_entries == MAX_IRQ_SOURCES)
 		panic("Max # of irq sources exceeded!!\n");
 }
 
 static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
 {
+	Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
+		" IRQ %02x, APIC ID %x, APIC LINT %02x\n",
+			m->mpc_irqtype, m->mpc_irqflag & 3,
+			(m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
+			m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
 	/*
 	 * Well it seems all SMP boards in existence
 	 * use ExtINT/LVT1 == LINT0 and
@@ -316,6 +325,122 @@
 	return num_processors;
 }
 
+static void __init construct_default_ioirq_mptable(int mpc_default_type)
+{
+	struct mpc_config_intsrc intsrc;
+	int i;
+
+	intsrc.mpc_type = MP_INTSRC;
+	intsrc.mpc_irqflag = 0;			/* conforming */
+	intsrc.mpc_srcbus = 0;
+	intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;
+
+	intsrc.mpc_irqtype = mp_INT;
+	for (i = 0; i < 16; i++) {
+		switch (mpc_default_type) {
+		case 2:
+			if (i == 0 || i == 13)
+				continue;	/* IRQ0 & IRQ13 not connected */
+			/* fall through */
+		default:
+			if (i == 2)
+				continue;	/* IRQ2 is never connected */
+		}
+
+		intsrc.mpc_srcbusirq = i;
+		intsrc.mpc_dstirq = i ? i : 2;		/* IRQ0 to INTIN2 */
+		MP_intsrc_info(&intsrc);
+	}
+
+	intsrc.mpc_irqtype = mp_ExtINT;
+	intsrc.mpc_srcbusirq = 0;
+	intsrc.mpc_dstirq = 0;				/* 8259A to INTIN0 */
+	MP_intsrc_info(&intsrc);
+}
+
+static inline void __init construct_default_ISA_mptable(int mpc_default_type)
+{
+	struct mpc_config_processor processor;
+	struct mpc_config_bus bus;
+	struct mpc_config_ioapic ioapic;
+	struct mpc_config_lintsrc lintsrc;
+	int linttypes[2] = { mp_ExtINT, mp_NMI };
+	int i;
+
+	/*
+	 * local APIC has default address
+	 */
+	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+	/*
+	 * 2 CPUs, numbered 0 & 1.
+	 */
+	processor.mpc_type = MP_PROCESSOR;
+	/* Either an integrated APIC or a discrete 82489DX. */
+	processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
+	processor.mpc_cpuflag = CPU_ENABLED;
+	processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
+				   (boot_cpu_data.x86_model << 4) |
+				   boot_cpu_data.x86_mask;
+	processor.mpc_featureflag = boot_cpu_data.x86_capability;
+	processor.mpc_reserved[0] = 0;
+	processor.mpc_reserved[1] = 0;
+	for (i = 0; i < 2; i++) {
+		processor.mpc_apicid = i;
+		MP_processor_info(&processor);
+	}
+
+	bus.mpc_type = MP_BUS;
+	bus.mpc_busid = 0;
+	switch (mpc_default_type) {
+		default:
+			printk("???\nUnknown standard configuration %d\n",
+				mpc_default_type);
+			/* fall through */
+		case 1:
+		case 5:
+			memcpy(bus.mpc_bustype, "ISA   ", 6);
+			break;
+		case 2:
+		case 6:
+		case 3:
+			memcpy(bus.mpc_bustype, "EISA  ", 6);
+			break;
+		case 4:
+		case 7:
+			memcpy(bus.mpc_bustype, "MCA   ", 6);
+	}
+	MP_bus_info(&bus);
+	if (mpc_default_type > 4) {
+		bus.mpc_busid = 1;
+		memcpy(bus.mpc_bustype, "PCI   ", 6);
+		MP_bus_info(&bus);
+	}
+
+	ioapic.mpc_type = MP_IOAPIC;
+	ioapic.mpc_apicid = 2;
+	ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
+	ioapic.mpc_flags = MPC_APIC_USABLE;
+	ioapic.mpc_apicaddr = 0xFEC00000;
+	MP_ioapic_info(&ioapic);
+
+	/*
+	 * We set up most of the low 16 IO-APIC pins according to MPS rules.
+	 */
+	construct_default_ioirq_mptable(mpc_default_type);
+
+	lintsrc.mpc_type = MP_LINTSRC;
+	lintsrc.mpc_irqflag = 0;		/* conforming */
+	lintsrc.mpc_srcbusid = 0;
+	lintsrc.mpc_srcbusirq = 0;
+	lintsrc.mpc_destapic = MP_APIC_ALL;
+	for (i = 0; i < 2; i++) {
+		lintsrc.mpc_irqtype = linttypes[i];
+		lintsrc.mpc_destapiclint = i;
+		MP_lintsrc_info(&lintsrc);
+	}
+}
+
 static struct intel_mp_floating *mpf_found;
 
 /*
@@ -332,83 +457,43 @@
 		printk("    Virtual Wire compatibility mode.\n");
 		pic_mode = 0;
 	}
-	/*
-	 * 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) {
+
 		printk("Default MP configuration #%d\n", mpf->mpf_feature1);
+		construct_default_ISA_mptable(mpf->mpf_feature1);
 
-		/*
-		 * local APIC has default address
-		 */
-		mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+	} else if (mpf->mpf_physptr) {
 
 		/*
-		 * 2 CPUs, numbered 0 & 1.
+		 * Read the physical hardware table.  Anything here will
+		 * override the defaults.
 		 */
-		phys_cpu_present_map = 3;
-		num_processors = 2;
+		smp_read_mpc((void *)mpf->mpf_physptr);
 
-		nr_ioapics = 1;
-		mp_ioapics[0].mpc_apicaddr = 0xFEC00000;
-		mp_ioapics[0].mpc_apicid = 2;
 		/*
-		 * Save the default type number, we
-		 * need it later to set the IO-APIC
-		 * up properly:
+		 * If there are no explicit MP IRQ entries, then we are
+		 * broken.  We set up most of the low 16 IO-APIC pins to
+		 * ISA defaults and hope it will work.
 		 */
-		mpc_default_type = mpf->mpf_feature1;
+		if (!mp_irq_entries) {
+			struct mpc_config_bus bus;
 
-		printk("Bus #0 is ");
-	}
+			printk("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n");
 
-	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;
-	}
-	if (mpf->mpf_feature1 > 4) {
-		printk("Bus #1 is PCI\n");
+			bus.mpc_type = MP_BUS;
+			bus.mpc_busid = 0;
+			memcpy(bus.mpc_bustype, "ISA   ", 6);
+			MP_bus_info(&bus);
 
-		/*
-		 * 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);
+			construct_default_ioirq_mptable(0);
+		}
+
+	} else
+		BUG();
 
 	printk("Processors: %d\n", num_processors);
 	/*
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.3.99-pre5/linux/arch/i386/kernel/mtrr.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/kernel/mtrr.c	Mon Apr 24 13:39:34 2000
@@ -289,7 +289,7 @@
 #define MTRRfix4K_F0000_MSR 0x26e
 #define MTRRfix4K_F8000_MSR 0x26f
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #  define MTRR_CHANGE_MASK_FIXED     0x01
 #  define MTRR_CHANGE_MASK_VARIABLE  0x02
 #  define MTRR_CHANGE_MASK_DEFTYPE   0x04
@@ -302,7 +302,7 @@
 #define LINE_SIZE      80
 #define JIFFIE_TIMEOUT 100
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #  define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
 #else
 #  define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \
@@ -767,7 +767,7 @@
 			    unsigned long size, mtrr_type type,
 			    int do_safe) = NULL;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 struct mtrr_var_range
 {
@@ -1015,7 +1015,7 @@
     printk ("mtrr: probably your BIOS does not setup all CPUs\n");
 }   /*  End Function mtrr_state_warn  */
 
-#endif  /*  __SMP__  */
+#endif  /*  CONFIG_SMP  */
 
 static char *attrib_to_str (int x)
 {
@@ -1110,7 +1110,7 @@
  *
  *	Memory type region registers control the caching on newer Intel and
  *	non Intel processors. This function allows drivers to request an
- *	MTRR is added. The details and hardware specifics of each processors
+ *	MTRR is added. The details and hardware specifics of each processor's
  *	implementation are hidden from the caller, but nevertheless the 
  *	caller should expect to need to provide a power of two size on an
  *	equivalent power of two boundary.
@@ -1125,13 +1125,13 @@
  *
  *	The available types are
  *
- *	MTRR_TYPE_UNCACHEABLE	-	No caching
+ *	%MTRR_TYPE_UNCACHEABLE	-	No caching
  *
- *	MTRR_TYPE_WRITEBACK	-	Write data back in bursts whenever
+ *	%MTRR_TYPE_WRITEBACK	-	Write data back in bursts whenever
  *
- *	MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
+ *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
  *
- *	MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
+ *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes
  *
  *	BUGS: Needs a quiet flag for the cases where drivers do not mind
  *	failures and do not wish system log messages to be sent.
@@ -1608,7 +1608,7 @@
 EXPORT_SYMBOL(mtrr_add);
 EXPORT_SYMBOL(mtrr_del);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 typedef struct
 {
@@ -1663,7 +1663,7 @@
     struct set_mtrr_context ctxt;
     unsigned char ccr[7];
     int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
-#ifdef __SMP__
+#ifdef CONFIG_SMP
     int i;
 #endif
 
@@ -1709,7 +1709,7 @@
 	setCx86 (CX86_CCR5, ccr[5]);
     }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
     for(i=0; i<7; i++) ccr_state[i] = ccr[i];
     for(i=0; i<8; i++)
       cyrix_get_arr(i,
@@ -1782,7 +1782,7 @@
     }
 }   /*  End Function mtrr_setup  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 static volatile unsigned long smp_changes_mask __initdata = 0;
 static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
@@ -1851,12 +1851,12 @@
 	break;
     }
 }   /*  End Function mtrr_init_secondary_cpu  */
-#endif  /*  __SMP__  */
+#endif  /*  CONFIG_SMP  */
 
 int __init mtrr_init(void)
 {
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
     switch (boot_cpu_data.x86_vendor)
     {
       case X86_VENDOR_AMD:
@@ -1866,7 +1866,7 @@
 	mtrr_state_warn (smp_changes_mask);
 	break;
     }
-#else  /*  __SMP__  */
+#else  /*  CONFIG_SMP  */
     mtrr_setup ();
     switch (boot_cpu_data.x86_vendor)
     {
@@ -1877,7 +1877,7 @@
         centaur_mcr_init ();
         break;
     }
-#endif  /*  !__SMP__  */
+#endif  /*  !CONFIG_SMP  */
 
 #ifdef CONFIG_PROC_FS
     proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- v2.3.99-pre5/linux/arch/i386/kernel/pci-irq.c	Wed Apr 12 10:02:34 2000
+++ linux/arch/i386/kernel/pci-irq.c	Sat Apr 15 21:12:11 2000
@@ -29,7 +29,7 @@
  * Avoid using: 13, 14 and 15 (FP error and IDE).
  * Penalize: 3, 4, 7, 12 (known ISA uses: serial, parallel and mouse)
  */
-unsigned int pcibios_irq_mask = ~0;
+unsigned int pcibios_irq_mask = 0xfff8;
 
 static unsigned pirq_penalty[16] = {
 	10000, 10000, 10000, 100, 100, 0, 0, 100,
@@ -305,10 +305,7 @@
 		return 0;
 	}
 	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
-	if (pcibios_irq_mask != ~0)
-		mask &= pcibios_irq_mask;
-	else
-		mask &= pirq_table->exclusive_irqs;
+	mask &= pcibios_irq_mask;
 
 	/* Find the best IRQ to assign */
 	newirq = 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.3.99-pre5/linux/arch/i386/kernel/process.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/i386/kernel/process.c	Tue Apr 25 17:45:43 2000
@@ -589,7 +589,6 @@
  * More important, however, is the fact that this allows us much
  * more flexibility.
  */
-extern int cpus_initialized;
 void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
 	struct thread_struct *prev = &prev_p->thread,
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.99-pre5/linux/arch/i386/kernel/setup.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/i386/kernel/setup.c	Tue Apr 25 17:45:43 2000
@@ -495,6 +495,10 @@
 			if (!memcmp(from+4, "nopentium", 9)) {
 				from += 9+4;
 				boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
+			} else if (!memcmp(from+4, "exactmap", 8)) {
+				from += 8+4;
+				e820.nr_map = 0;
+				usermem = 1;
 			} else {
 				/* If the user specifies memory size, we
 				 * blow away any automatically generated
@@ -1531,8 +1535,7 @@
 	return p - buffer;
 }
 
-int cpus_initialized = 0;
-unsigned long cpu_initialized = 0;
+static unsigned long cpu_initialized __initdata = 0;
 
 /*
  * cpu_init() initializes state that is per-CPU. Some data is already
@@ -1549,7 +1552,6 @@
 		printk("CPU#%d already initialized!\n", nr);
 		for (;;) __sti();
 	}
-	cpus_initialized++;
 	printk("Initializing CPU#%d\n", nr);
 
 	if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.3.99-pre5/linux/arch/i386/kernel/signal.c	Mon Mar 27 08:08:21 2000
+++ linux/arch/i386/kernel/signal.c	Tue Apr 25 17:52:01 2000
@@ -339,9 +339,9 @@
 	int tmp, err = 0;
 
 	tmp = 0;
-	__asm__("movl %%gs,%w0" : "=r"(tmp): "0"(tmp));
+	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
 	err |= __put_user(tmp, (unsigned int *)&sc->gs);
-	__asm__("movl %%fs,%w0" : "=r"(tmp): "0"(tmp));
+	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
 	err |= __put_user(tmp, (unsigned int *)&sc->fs);
 
 	err |= __put_user(regs->xes, (unsigned int *)&sc->es);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.99-pre5/linux/arch/i386/kernel/smp.c	Sat Feb 12 11:22:10 2000
+++ linux/arch/i386/kernel/smp.c	Wed Apr 12 09:33:20 2000
@@ -111,108 +111,26 @@
  * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
  */
 
-static unsigned int cached_APIC_ICR;
-static unsigned int cached_APIC_ICR2;
-
-/*
- * Caches reserved bits, APIC reads are (mildly) expensive
- * and force otherwise unnecessary CPU synchronization.
- *
- * (We could cache other APIC registers too, but these are the
- * main ones used in RL.)
- */
-#define slow_ICR (apic_read(APIC_ICR) & ~0xFDFFF)
-#define slow_ICR2 (apic_read(APIC_ICR2) & 0x00FFFFFF)
-
-void cache_APIC_registers (void)
-{
-	cached_APIC_ICR = slow_ICR;
-	cached_APIC_ICR2 = slow_ICR2;
-	mb();
-}
-
-static inline unsigned int __get_ICR (void)
-{
-#if FORCE_READ_AROUND_WRITE
-	/*
-	 * Wait for the APIC to become ready - this should never occur. It's
-	 * a debugging check really.
-	 */
-	int count = 0;
-	unsigned int cfg;
-
-	while (count < 1000)
-	{
-		cfg = slow_ICR;
-		if (!(cfg&(1<<12)))
-			return cfg;
-		printk("CPU #%d: ICR still busy [%08x]\n",
-					smp_processor_id(), cfg);
-		irq_err_count++;
-		count++;
-		udelay(10);
-	}
-	printk("CPU #%d: previous IPI still not cleared after 10mS\n",
-			smp_processor_id());
-	return cfg;
-#else
-	return cached_APIC_ICR;
-#endif
-}
-
-static inline unsigned int __get_ICR2 (void)
-{
-#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
-#if LOGICAL_DELIVERY
-		|APIC_DEST_LOGICAL
-#endif
-		;
-
-	return cfg;
+	return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
 }
 
 static inline int __prepare_ICR2 (unsigned int mask)
 {
-	unsigned int cfg;
-
-	cfg = __get_ICR2();
-#if LOGICAL_DELIVERY
-	cfg |= SET_APIC_DEST_FIELD(mask);
-#else
-	cfg |= SET_APIC_DEST_FIELD(mask);
-#endif
-
-	return cfg;
+	return SET_APIC_DEST_FIELD(mask);
 }
 
 static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
 {
+	/*
+	 * Subtle. In the case of the 'never do double writes' workaround
+	 * we have to lock out interrupts to be safe.  As we don't care
+	 * of the value read we use an atomic rmw access to avoid costly
+	 * cli/sti.  Otherwise we use an even cheaper single atomic write
+	 * to the APIC.
+	 */
 	unsigned int cfg;
-/*
- * Subtle. In the case of the 'never do double writes' workaround we
- * 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_READ_AROUND_WRITE
-	unsigned long flags;
-
-	__save_flags(flags);
-	__cli();
-#endif
 
 	/*
 	 * No need to touch the target chip field
@@ -222,10 +140,7 @@
 	/*
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
-	apic_write(APIC_ICR, cfg);
-#if FORCE_READ_AROUND_WRITE
-	__restore_flags(flags);
-#endif
+	apic_write_around(APIC_ICR, cfg);
 }
 
 static inline void send_IPI_allbutself(int vector)
@@ -252,19 +167,16 @@
 static inline void send_IPI_mask(int mask, int vector)
 {
 	unsigned long cfg;
-#if FORCE_READ_AROUND_WRITE
 	unsigned long flags;
 
 	__save_flags(flags);
 	__cli();
-#endif
 
 	/*
 	 * prepare target chip field
 	 */
-
 	cfg = __prepare_ICR2(mask);
-	apic_write(APIC_ICR2, cfg);
+	apic_write_around(APIC_ICR2, cfg);
 
 	/*
 	 * program the ICR 
@@ -274,10 +186,8 @@
 	/*
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
-	apic_write(APIC_ICR, cfg);
-#if FORCE_READ_AROUND_WRITE
+	apic_write_around(APIC_ICR, cfg);
 	__restore_flags(flags);
-#endif
 }
 
 /*
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- v2.3.99-pre5/linux/arch/i386/kernel/smpboot.c	Tue Feb  1 01:35:43 2000
+++ linux/arch/i386/kernel/smpboot.c	Wed Apr 12 09:33:20 2000
@@ -28,6 +28,7 @@
  *					from Jose Renau
  *		Ingo Molnar	:	various cleanups and rewrites
  *		Tigran Aivazian	:	fixed "0.00 in /proc/uptime on SMP" bug.
+ *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs
  */
 
 #include <linux/config.h>
@@ -489,11 +490,43 @@
 	return do_fork(CLONE_VM|CLONE_PID, 0, &regs);
 }
 
+#if APIC_DEBUG
+static inline void inquire_remote_apic(int apicid)
+{
+	int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
+	char *names[] = { "ID", "VERSION", "SPIV" };
+	int timeout, status;
+
+	printk("Inquiring remote APIC #%d...\n", apicid);
+
+	for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) {
+		printk("... APIC #%d %s: ", apicid, names[i]);
+
+		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+		apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
+
+		timeout = 0;
+		do {
+			udelay(100);
+			status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
+		} while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
+
+		switch (status) {
+		case APIC_ICR_RR_VALID:
+			status = apic_read(APIC_RRR);
+			printk("%08x\n", status);
+			break;
+		default:
+			printk("failed\n");
+		}
+	}
+}
+#endif
+
 static void __init do_boot_cpu (int apicid)
 {
-	unsigned long cfg;
 	struct task_struct *idle;
-	unsigned long send_status, accept_status;
+	unsigned long send_status, accept_status, boot_status, maxlvt;
 	int timeout, num_starts, j, cpu;
 	unsigned long start_eip;
 
@@ -527,7 +560,7 @@
 	start_eip = setup_trampoline();
 
 	/* So we see what's up   */
-	printk("Booting processor %d eip %lx\n", cpu, start_eip);
+	printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
 	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
 
 	/*
@@ -549,16 +582,17 @@
 	 * Be paranoid about clearing APIC errors.
 	 */
 	if (APIC_INTEGRATED(apic_version[apicid])) {
-		apic_readaround(APIC_SPIV);
+		apic_read_around(APIC_SPIV);
 		apic_write(APIC_ESR, 0);
-		accept_status = (apic_read(APIC_ESR) & 0xEF);
+		apic_read(APIC_ESR);
 	}
 
 	/*
 	 * Status is now clean
 	 */
-	send_status = 	0;
+	send_status = 0;
 	accept_status = 0;
+	boot_status = 0;
 
 	/*
 	 * Starting actual IPI sequence...
@@ -567,37 +601,41 @@
 	Dprintk("Asserting INIT.\n");
 
 	/*
-	 * Turn INIT on
-	 */
-	cfg = apic_read(APIC_ICR2);
-	cfg &= 0x00FFFFFF;
-
-	/*
-	 * Target chip
+	 * Turn INIT on target chip
 	 */
-	apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid));
+	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 
 	/*
 	 * 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);
+	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+				| APIC_DM_INIT);
+
+	Dprintk("Waiting for send to finish...\n");
+	timeout = 0;
+	do {
+		Dprintk("+");
+		udelay(100);
+		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+	} while (send_status && (timeout++ < 1000));
+
+	mdelay(10);
 
-	udelay(200);
 	Dprintk("Deasserting INIT.\n");
 
 	/* Target chip */
-	cfg = apic_read(APIC_ICR2);
-	cfg &= 0x00FFFFFF;
-	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(apicid));
+	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 
 	/* Send IPI */
-	cfg = apic_read(APIC_ICR);
-	cfg &= ~0xCDFFF;
-	cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT);
-	apic_write(APIC_ICR, cfg);
+	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+
+	Dprintk("Waiting for send to finish...\n");
+	timeout = 0;
+	do {
+		Dprintk("+");
+		udelay(100);
+		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+	} while (send_status && (timeout++ < 1000));
 
 	/*
 	 * Should we send STARTUP IPIs ?
@@ -616,9 +654,11 @@
 	 */
 	Dprintk("#startup loops: %d.\n", num_starts);
 
+	maxlvt = get_maxlvt();
+
 	for (j = 1; j <= num_starts; j++) {
 		Dprintk("Sending STARTUP #%d.\n",j);
-		apic_readaround(APIC_SPIV);
+		apic_read_around(APIC_SPIV);
 		apic_write(APIC_ESR, 0);
 		apic_read(APIC_ESR);
 		Dprintk("After apic_write.\n");
@@ -628,17 +668,12 @@
 		 */
 
 		/* Target chip */
-		cfg = apic_read(APIC_ICR2);
-		cfg &= 0x00FFFFFF;
-		apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid));
+		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 
 		/* 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);
+		apic_write_around(APIC_ICR, APIC_DM_STARTUP
+					| (start_eip >> 12));
 
 		Dprintk("Startup point 1.\n");
 
@@ -647,13 +682,20 @@
 		do {
 			Dprintk("+");
 			udelay(100);
-			send_status = apic_read(APIC_ICR) & 0x1000;
+			send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
 		} while (send_status && (timeout++ < 1000));
 
 		/*
 		 * Give the other CPU some time to accept the IPI.
 		 */
 		udelay(200);
+		/*
+		 * Due to the Pentium erratum 3AP.
+		 */
+		if (maxlvt > 3) {
+			apic_read_around(APIC_SPIV);
+			apic_write(APIC_ESR, 0);
+		}
 		accept_status = (apic_read(APIC_ESR) & 0xEF);
 		if (send_status || accept_status)
 			break;
@@ -676,7 +718,7 @@
 		/*
 		 * Wait 5s total for a response
 		 */
-		for (timeout = 0; timeout < 1000000000; timeout++) {
+		for (timeout = 0; timeout < 50000; timeout++) {
 			if (test_bit(cpu, &cpu_callin_map))
 				break;	/* It has booted */
 			udelay(100);
@@ -687,15 +729,22 @@
 			Dprintk("OK.\n");
 			printk("CPU%d: ", cpu);
 			print_cpu_info(&cpu_data[cpu]);
+			Dprintk("CPU has booted.\n");
 		} else {
+			boot_status = 1;
 			if (*((volatile unsigned char *)phys_to_virt(8192))
-					== 0xA5) /* trampoline code not run */
+					== 0xA5)
+				/* trampoline started but...? */
 				printk("Stuck ??\n");
 			else
-				printk("CPU booted but not responding.\n");
+				/* trampoline code not run */
+				printk("Not responding.\n");
+#if APIC_DEBUG
+			inquire_remote_apic(apicid);
+#endif
 		}
-		Dprintk("CPU has booted.\n");
-	} else {
+	}
+	if (send_status || accept_status || boot_status) {
 		x86_cpu_to_apicid[cpu] = -1;
 		x86_apicid_to_cpu[apicid] = -1;
 		cpucount--;
@@ -858,6 +907,7 @@
 		Dprintk("Getting LVT1: %x\n", reg);
 	}
 
+	connect_bsp_APIC();
 	setup_local_APIC();
 
 	if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id)
@@ -877,7 +927,7 @@
 
 		if (!(phys_cpu_present_map & (1 << apicid)))
 			continue;
-		if ((max_cpus >= 0) && (max_cpus < cpucount+1))
+		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
 			continue;
 
 		do_boot_cpu(apicid);
@@ -934,7 +984,6 @@
 		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
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.3.99-pre5/linux/arch/i386/kernel/traps.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/i386/kernel/traps.c	Tue Apr 25 17:52:01 2000
@@ -696,7 +696,7 @@
 		((limit) & 0x0ffff); }
 
 #define _set_tssldt_desc(n,addr,limit,type) \
-__asm__ __volatile__ ("movw %3,0(%2)\n\t" \
+__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
 	"movw %%ax,2(%2)\n\t" \
 	"rorl $16,%%eax\n\t" \
 	"movb %%al,4(%2)\n\t" \
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c
--- v2.3.99-pre5/linux/arch/i386/kernel/visws_apic.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/i386/kernel/visws_apic.c	Wed Apr 12 09:33:20 2000
@@ -376,7 +376,7 @@
 	for (i = 0; i < 16; i++) {
 		irq_desc[i].status = IRQ_DISABLED;
 		irq_desc[i].action = 0;
-		irq_desc[i].depth = 0;
+		irq_desc[i].depth = 1;
 
 		/*
 		 * Cobalt IRQs are mapped to standard ISA
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/lib/delay.c linux/arch/i386/lib/delay.c
--- v2.3.99-pre5/linux/arch/i386/lib/delay.c	Tue Mar 14 19:10:39 2000
+++ linux/arch/i386/lib/delay.c	Mon Apr 24 13:39:34 2000
@@ -10,11 +10,12 @@
  *	we have to worry about.
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <asm/delay.h>
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #include <asm/smp.h>
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.3.99-pre5/linux/arch/i386/mm/fault.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/i386/mm/fault.c	Mon Apr 24 15:48:55 2000
@@ -51,7 +51,7 @@
 	start &= PAGE_MASK;
 
 	for (;;) {
-		if (handle_mm_fault(current, vma, start, 1) <= 0)
+		if (handle_mm_fault(current->mm, vma, start, 1) <= 0)
 			goto bad_area;
 		if (!size)
 			break;
@@ -193,7 +193,7 @@
 	 * the fault.
 	 */
 	{
-		int fault = handle_mm_fault(tsk, vma, address, write);
+		int fault = handle_mm_fault(mm, vma, address, write);
 		if (fault < 0)
 			goto out_of_memory;
 		if (!fault)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/Makefile linux/arch/ia64/Makefile
--- v2.3.99-pre5/linux/arch/ia64/Makefile	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/Makefile	Fri Apr 21 15:21:23 2000
@@ -9,6 +9,7 @@
 #
 
 NM := $(CROSS_COMPILE)nm -B
+AWK := awk
 
 LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds
 # next line is for HP compiler backend:
@@ -16,10 +17,10 @@
 # The next line is needed when compiling with the July snapshot of the Cygnus compiler:
 #EXTRA	= -D__GCC_DOESNT_KNOW_IN_REGS__
 # next two lines are for the September snapshot of the Cygnus compiler:
-AFLAGS += -D__GCC_MULTIREG_RETVALS__
+AFLAGS += -D__GCC_MULTIREG_RETVALS__ -Wa,-x
 EXTRA	= -D__GCC_MULTIREG_RETVALS__
 
-CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127
+CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127
 
 ifdef CONFIG_IA64_GENERIC
 	CORE_FILES      :=      arch/$(ARCH)/hp/hp.a	\
@@ -34,14 +35,14 @@
 
 else # !GENERIC
 
-ifeq ($(CONFIG_IA64_HP_SIM),y)
+ifdef CONFIG_IA64_HP_SIM
         SUBDIRS         :=      arch/$(ARCH)/hp		\
                                 $(SUBDIRS)
         CORE_FILES      :=      arch/$(ARCH)/hp/hp.a	\
                                 $(CORE_FILES)
 endif
 
-ifeq ($(CONFIG_IA64_SGI_SN1_SIM),y)
+ifdef CONFIG_IA64_SGI_SN1_SIM
         SUBDIRS         :=      arch/$(ARCH)/sn/sn1	\
 				arch/$(ARCH)/sn		\
 				$(SUBDIRS)
@@ -49,14 +50,14 @@
 				$(CORE_FILES)
 endif
 
-ifeq ($(CONFIG_IA64_SOFTSDV),y)
+ifdef CONFIG_IA64_SOFTSDV
         SUBDIRS         :=      arch/$(ARCH)/dig	\
 				$(SUBDIRS)
         CORE_FILES      :=      arch/$(ARCH)/dig/dig.a	\
 				$(CORE_FILES)
 endif
 
-ifeq ($(CONFIG_IA64_DIG),y)
+ifdef CONFIG_IA64_DIG
         SUBDIRS         :=      arch/$(ARCH)/dig	\
 				$(SUBDIRS)
         CORE_FILES      :=      arch/$(ARCH)/dig/dig.a	\
@@ -65,14 +66,9 @@
 
 endif # !GENERIC
 
-ifeq ($(CONFIG_IA32_SUPPORT),y)
+ifdef CONFIG_IA32_SUPPORT
 	SUBDIRS		:=	arch/$(ARCH)/ia32 $(SUBDIRS)
 	CORE_FILES	:=	arch/$(ARCH)/ia32/ia32.o $(CORE_FILES)
-endif
-
-ifdef CONFIG_KDB
-	LIBS := $(LIBS) $(TOPDIR)/arch/$(ARCH)/kdb/kdb.a
-	SUBDIRS := $(SUBDIRS) arch/$(ARCH)/kdb
 endif
 
 HEAD := arch/$(ARCH)/kernel/head.o arch/ia64/kernel/init_task.o
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/config.in linux/arch/ia64/config.in
--- v2.3.99-pre5/linux/arch/ia64/config.in	Tue Apr 11 15:09:12 2000
+++ linux/arch/ia64/config.in	Fri Apr 21 15:21:23 2000
@@ -4,6 +4,8 @@
 comment 'General setup'
 
 define_bool CONFIG_IA64 y
+define_bool CONFIG_ITANIUM y	# easy choice for now... ;-)
+
 define_bool CONFIG_ISA n
 define_bool CONFIG_SBUS n
 
@@ -25,7 +27,7 @@
 	bool '  Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS
 	bool '  Enable Lion hacks' CONFIG_IA64_LION_HACKS
 	bool '  Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU
-	bool '  Get PCI IRQ routing from firmware/ACPI'	CONFIG_IA64_IRQ_ACPI
+	bool '  Enable IA64 Machine Check Abort' CONFIG_IA64_MCA
 fi
 
 if [ "$CONFIG_IA64_GENERIC" = "y" ]; then
@@ -185,10 +187,5 @@
 bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
 bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
 bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS
-bool 'Built-in Kernel Debugger support' CONFIG_KDB
-if [ "$CONFIG_KDB" = "y" ]; then
-  bool 'Compile the kernel with frame pointers' CONFIG_KDB_FRAMEPTR
-  int  'KDB Kernel Symbol Table size?' CONFIG_KDB_STBSIZE 10000
-fi
 
 endmenu
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/defconfig linux/arch/ia64/defconfig
--- v2.3.99-pre5/linux/arch/ia64/defconfig	Tue Apr 11 15:09:12 2000
+++ linux/arch/ia64/defconfig	Thu Apr 13 22:54:26 2000
@@ -115,8 +115,8 @@
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/dig/Makefile linux/arch/ia64/dig/Makefile
--- v2.3.99-pre5/linux/arch/ia64/dig/Makefile	Tue Apr 11 15:09:12 2000
+++ linux/arch/ia64/dig/Makefile	Fri Apr 21 15:21:23 2000
@@ -15,7 +15,7 @@
 O_TARGET        = dig.a
 O_OBJS          = iosapic.o setup.o
 
-ifeq ($(CONFIG_IA64_GENERIC),y)
+ifdef CONFIG_IA64_GENERIC
 O_OBJS		+= machvec.o
 endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/dig/iosapic.c linux/arch/ia64/dig/iosapic.c
--- v2.3.99-pre5/linux/arch/ia64/dig/iosapic.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/dig/iosapic.c	Fri Apr 21 15:21:23 2000
@@ -7,16 +7,20 @@
  * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
+ *
+ * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O APIC code.
+ *				In particular, we now have separate handlers for edge
+ *				and level triggered interrupts.
  */
 #include <linux/config.h>
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/string.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/iosapic.h>
@@ -27,172 +31,19 @@
 
 #undef DEBUG_IRQ_ROUTING
 
-/*
- * IRQ vectors 0..15 are treated as the legacy interrupts of the PC-AT
- * platform.  No new drivers should ever ask for specific irqs, but we
- * provide compatibility here in case there is an old driver that does
- * ask for specific irqs (serial, keyboard, stuff like that).  Since
- * IA-64 doesn't allow irq 0..15 to be used for external interrupts
- * anyhow, this in no way prevents us from doing the Right Thing
- * with new drivers.
- */
+static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;
+
 struct iosapic_vector iosapic_vector[NR_IRQS] = {
 	[0 ... NR_IRQS-1] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
 };
 
-#ifndef CONFIG_IA64_IRQ_ACPI
-/*
- * Defines the default interrupt routing information for the LION platform
- * XXX - this information should be obtained from the ACPI and hardcoded since
- * we do not have ACPI AML support.
- */
-
-struct intr_routing_entry intr_routing[] = {
-      {0,0,0,2,0,0,0,0},
-      {0,0,1,1,0,0,0,0},
-      {0,0,2,0xff,0,0,0,0},
-      {0,0,3,3,0,0,0,0},
-      {0,0,4,4,0,0,0,0},
-      {0,0,5,5,0,0,0,0},
-      {0,0,6,6,0,0,0,0},
-      {0,0,7,7,0,0,0,0},
-      {0,0,8,8,0,0,0,0},
-      {0,0,9,9,0,0,0,0},
-      {0,0,10,10,0,0,0,0},
-      {0,0,11,11,0,0,0,0},
-      {0,0,12,12,0,0,0,0},
-      {0,0,13,13,0,0,0,0},
-      {0,0,14,14,0,0,0,0},
-      {0,0,15,15,0,0,0,0},
-#ifdef CONFIG_IA64_LION_HACKS
-      {1, 0, 0x04, 16, 0, 0, 1, 1},	/* bus 0, device id 1, INTA */
-      {1, 0, 0x05, 26, 0, 0, 1, 1},	/* bus 0, device id 1, INTB */
-      {1, 0, 0x06, 36, 0, 0, 1, 1},	/* bus 0, device id 1, INTC */
-      {1, 0, 0x07, 42, 0, 0, 1, 1},	/* bus 0, device id 1, INTD */
-
-      {1, 0, 0x08, 17, 0, 0, 1, 1},	/* bus 0, device id 2, INTA */
-      {1, 0, 0x09, 27, 0, 0, 1, 1},	/* bus 0, device id 2, INTB */
-      {1, 0, 0x0a, 37, 0, 0, 1, 1},	/* bus 0, device id 2, INTC */
-      {1, 0, 0x0b, 42, 0, 0, 1, 1},	/* bus 0, device id 2, INTD */
-
-      {1, 0, 0x0f, 50, 0, 0, 1, 1},	/* bus 0, device id 3, INTD */
-
-      {1, 0, 0x14, 51, 0, 0, 1, 1},	/* bus 0, device id 5, INTA */
-
-      {1, 0, 0x18, 49, 0, 0, 1, 1},	/* bus 0, device id 6, INTA */
-
-      {1, 1, 0x04, 18, 0, 0, 1, 1},	/* bus 1, device id 1, INTA */
-      {1, 1, 0x05, 28, 0, 0, 1, 1},	/* bus 1, device id 1, INTB */
-      {1, 1, 0x06, 38, 0, 0, 1, 1},	/* bus 1, device id 1, INTC */
-      {1, 1, 0x07, 43, 0, 0, 1, 1},	/* bus 1, device id 1, INTD */
-
-      {1, 1, 0x08, 48, 0, 0, 1, 1},	/* bus 1, device id 2, INTA */
-
-      {1, 1, 0x0c, 19, 0, 0, 1, 1},	/* bus 1, device id 3, INTA */
-      {1, 1, 0x0d, 29, 0, 0, 1, 1},	/* bus 1, device id 3, INTB */
-      {1, 1, 0x0e, 38, 0, 0, 1, 1},	/* bus 1, device id 3, INTC */
-      {1, 1, 0x0f, 44, 0, 0, 1, 1},	/* bus 1, device id 3, INTD */
-
-      {1, 1, 0x10, 20, 0, 0, 1, 1},	/* bus 1, device id 4, INTA */
-      {1, 1, 0x11, 30, 0, 0, 1, 1},	/* bus 1, device id 4, INTB */
-      {1, 1, 0x12, 39, 0, 0, 1, 1},	/* bus 1, device id 4, INTC */
-      {1, 1, 0x13, 45, 0, 0, 1, 1},	/* bus 1, device id 4, INTD */
-
-      {1, 2, 0x04, 21, 0, 0, 1, 1},	/* bus 2, device id 1, INTA */
-      {1, 2, 0x05, 31, 0, 0, 1, 1},	/* bus 2, device id 1, INTB */
-      {1, 2, 0x06, 39, 0, 0, 1, 1},	/* bus 2, device id 1, INTC */
-      {1, 2, 0x07, 45, 0, 0, 1, 1},	/* bus 2, device id 1, INTD */
-
-      {1, 2, 0x08, 22, 0, 0, 1, 1},	/* bus 2, device id 2, INTA */
-      {1, 2, 0x09, 32, 0, 0, 1, 1},	/* bus 2, device id 2, INTB */
-      {1, 2, 0x0a, 40, 0, 0, 1, 1},	/* bus 2, device id 2, INTC */
-      {1, 2, 0x0b, 46, 0, 0, 1, 1},	/* bus 2, device id 2, INTD */
-
-      {1, 2, 0x0c, 23, 0, 0, 1, 1},	/* bus 2, device id 3, INTA */
-      {1, 2, 0x0d, 33, 0, 0, 1, 1},	/* bus 2, device id 3, INTB */
-      {1, 2, 0x0e, 40, 0, 0, 1, 1},	/* bus 2, device id 3, INTC */
-      {1, 2, 0x0f, 46, 0, 0, 1, 1},	/* bus 2, device id 3, INTD */
-
-      {1, 3, 0x04, 24, 0, 0, 1, 1},	/* bus 3, device id 1, INTA */
-      {1, 3, 0x05, 34, 0, 0, 1, 1},	/* bus 3, device id 1, INTB */
-      {1, 3, 0x06, 41, 0, 0, 1, 1},	/* bus 3, device id 1, INTC */
-      {1, 3, 0x07, 47, 0, 0, 1, 1},	/* bus 3, device id 1, INTD */
-
-      {1, 3, 0x08, 25, 0, 0, 1, 1},	/* bus 3, device id 2, INTA */
-      {1, 3, 0x09, 35, 0, 0, 1, 1},	/* bus 3, device id 2, INTB */
-      {1, 3, 0x0a, 41, 0, 0, 1, 1},	/* bus 3, device id 2, INTC */
-      {1, 3, 0x0b, 47, 0, 0, 1, 1},	/* bus 3, device id 2, INTD */
-#else
-      /*
-       * BigSur platform, bus 0, device 1,2,4 and bus 1 device 0-3
-       */
-      {1,1,0x0,19,0,0,1,1},		/* bus 1, device id 0, INTA */
-      {1,1,0x1,18,0,0,1,1},		/* bus 1, device id 0, INTB */
-      {1,1,0x2,17,0,0,1,1},		/* bus 1, device id 0, INTC */
-      {1,1,0x3,16,0,0,1,1},		/* bus 1, device id 0, INTD */
-
-      {1,1,0x4,23,0,0,1,1},		/* bus 1, device id 1, INTA */
-      {1,1,0x5,22,0,0,1,1},		/* bus 1, device id 1, INTB */
-      {1,1,0x6,21,0,0,1,1},		/* bus 1, device id 1, INTC */
-      {1,1,0x7,20,0,0,1,1},		/* bus 1, device id 1, INTD */
-
-      {1,1,0x8,27,0,0,1,1},		/* bus 1, device id 2, INTA */
-      {1,1,0x9,26,0,0,1,1},		/* bus 1, device id 2, INTB */
-      {1,1,0xa,25,0,0,1,1},		/* bus 1, device id 2, INTC */
-      {1,1,0xb,24,0,0,1,1},		/* bus 1, device id 2, INTD */
-
-      {1,1,0xc,31,0,0,1,1},		/* bus 1, device id 3, INTA */
-      {1,1,0xd,30,0,0,1,1},		/* bus 1, device id 3, INTB */
-      {1,1,0xe,29,0,0,1,1},		/* bus 1, device id 3, INTC */
-      {1,1,0xf,28,0,0,1,1},		/* bus 1, device id 3, INTD */
-
-      {1,0,0x4,35,0,0,1,1},		/* bus 0, device id 1, INTA */
-      {1,0,0x5,34,0,0,1,1},		/* bus 0, device id 1, INTB */
-      {1,0,0x6,33,0,0,1,1},		/* bus 0, device id 1, INTC */
-      {1,0,0x7,32,0,0,1,1},		/* bus 0, device id 1, INTD */
-
-      {1,0,0x8,39,0,0,1,1},		/* bus 0, device id 2, INTA */
-      {1,0,0x9,38,0,0,1,1},		/* bus 0, device id 2, INTB */
-      {1,0,0xa,37,0,0,1,1},		/* bus 0, device id 2, INTC */
-      {1,0,0xb,36,0,0,1,1},		/* bus 0, device id 2, INTD */
-
-      {1,0,0x10,43,0,0,1,1},		/* bus 0, device id 4, INTA */
-      {1,0,0x11,42,0,0,1,1},		/* bus 0, device id 4, INTB */
-      {1,0,0x12,41,0,0,1,1},		/* bus 0, device id 4, INTC */
-      {1,0,0x13,40,0,0,1,1},		/* bus 0, device id 4, INTD */
-
-      {1,0,0x14,17,0,0,1,1},		/* bus 0, device id 5, INTA */
-      {1,0,0x18,18,0,0,1,1},		/* bus 0, device id 6, INTA */
-      {1,0,0x1c,19,0,0,1,1},		/* bus 0, device id 7, INTA */
-#endif
-      {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
-};
-
-int
-iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin)
-{
-	int     i = -1;
-
-	while (intr_routing[++i].srcbus != 0xff) {
-		if (intr_routing[i].srcbus == BUS_PCI) {
-			if ((intr_routing[i].srcbusirq == ((slot << 2) | pci_pin)) 
-			    && (intr_routing[i].srcbusno == bus)) {
-				return(intr_routing[i].iosapic_pin);
-			}
-		}
-	}
-	return -1;
-}
-
-#else /* CONFIG_IA64_IRQ_ACPI */
-
 /*
  * find the IRQ in the IOSAPIC map for the PCI device on bus/slot/pin
  */
 int
-iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin)
+iosapic_get_PCI_irq_vector (int bus, int slot, int pci_pin)
 {
-	int	i;
+	int i;
 
 	for (i = 0; i < NR_IRQS; i++) {
 		if ((iosapic_bustype(i) == BUS_PCI) &&
@@ -201,17 +52,15 @@
 			return i;
 		}
 	}
-
 	return -1;
 }
-#endif /* !CONFIG_IA64_IRQ_ACPI */
 
 static void
 set_rte (unsigned long iosapic_addr, int entry, int pol, int trigger, int delivery,
 	 long dest, int vector)
 {
-	int low32;
-	int high32;
+	u32 low32;
+	u32 high32;
 
 	low32 = ((pol << IO_SAPIC_POLARITY_SHIFT) |
 		 (trigger << IO_SAPIC_TRIGGER_SHIFT) |
@@ -221,81 +70,137 @@
 	/* dest contains both id and eid */
 	high32 = (dest << IO_SAPIC_DEST_SHIFT);	
 
-	/*
-	 * program the rte 
-	 */
 	writel(IO_SAPIC_RTE_HIGH(entry), iosapic_addr + IO_SAPIC_REG_SELECT);
 	writel(high32, iosapic_addr + IO_SAPIC_WINDOW);
 	writel(IO_SAPIC_RTE_LOW(entry), iosapic_addr + IO_SAPIC_REG_SELECT);
 	writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
 }
 
+static void
+nop (unsigned int irq)
+{
+	/* do nothing... */
+}
 
 static void 
-enable_pin (unsigned int pin, unsigned long iosapic_addr)
+mask_irq (unsigned int irq)
 {
-        int low32;
+	unsigned long flags, iosapic_addr = iosapic_addr(irq);
+	u32 low32;
 
-        writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT);
-        low32 = readl(iosapic_addr + IO_SAPIC_WINDOW);
+	spin_lock_irqsave(&iosapic_lock, flags);
+	{
+		writel(IO_SAPIC_RTE_LOW(iosapic_pin(irq)), iosapic_addr + IO_SAPIC_REG_SELECT);
+		low32 = readl(iosapic_addr + IO_SAPIC_WINDOW);
 
-        low32 &= ~(1 << IO_SAPIC_MASK_SHIFT);    /* Zero only the mask bit */
-        writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
+		low32 |= (1 << IO_SAPIC_MASK_SHIFT);    /* Zero only the mask bit */
+		writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
+	}
+	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
-
 static void 
-disable_pin (unsigned int pin, unsigned long iosapic_addr)
+unmask_irq (unsigned int irq)
 {
-        int low32;
+	unsigned long flags, iosapic_addr = iosapic_addr(irq);
+	u32 low32;
 
-        writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT);
-        low32 = readl(iosapic_addr + IO_SAPIC_WINDOW);
+	spin_lock_irqsave(&iosapic_lock, flags);
+	{
+		writel(IO_SAPIC_RTE_LOW(iosapic_pin(irq)), iosapic_addr + IO_SAPIC_REG_SELECT);
+		low32 = readl(iosapic_addr + IO_SAPIC_WINDOW);
 
-        low32 |= (1 << IO_SAPIC_MASK_SHIFT);     /* Set only the mask bit */
-        writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
+		low32 &= ~(1 << IO_SAPIC_MASK_SHIFT);    /* Zero only the mask bit */
+		writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
+	}
+	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
-#define iosapic_shutdown_irq	iosapic_disable_irq
 
-static unsigned int
-iosapic_startup_irq (unsigned int irq)
+static void
+iosapic_set_affinity (unsigned int irq, unsigned long mask)
 {
-	int pin;
+	printk("iosapic_set_affinity: not implemented yet\n");
+}
+
+/*
+ * Handlers for level-triggered interrupts.
+ */
 
-	pin = iosapic_pin(irq);
-	if (pin < 0)
-		/* happens during irq auto probing... */
-		return 0;
-	set_rte(iosapic_addr(irq), pin, iosapic_polarity(irq), iosapic_trigger(irq), 
-		iosapic_dmode(irq), (ia64_get_lid() >> 16) & 0xffff, irq);
-	enable_pin(pin, iosapic_addr(irq));
+static unsigned int
+iosapic_startup_level_irq (unsigned int irq)
+{
+	unmask_irq(irq);
 	return 0;
 }
 
 static void
-iosapic_enable_irq (unsigned int irq)
+iosapic_end_level_irq (unsigned int irq)
 {
-	int pin = iosapic_pin(irq);
+	writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI);
+}
+
+#define iosapic_shutdown_level_irq	mask_irq
+#define iosapic_enable_level_irq	unmask_irq
+#define iosapic_disable_level_irq	mask_irq
+#define iosapic_ack_level_irq		nop
+
+struct hw_interrupt_type irq_type_iosapic_level = {
+	typename:	"IO-SAPIC-level",
+	startup:	iosapic_startup_level_irq,
+	shutdown:	iosapic_shutdown_level_irq,
+	enable:		iosapic_enable_level_irq,
+	disable:	iosapic_disable_level_irq,
+	ack:		iosapic_ack_level_irq,
+	end:		iosapic_end_level_irq,
+	set_affinity:	iosapic_set_affinity
+};
+
+/*
+ * Handlers for edge-triggered interrupts.
+ */
 
-	if (pin < 0)
-		/* happens during irq auto probing... */
-		return;
-	enable_pin(pin, iosapic_addr(irq));
+static unsigned int
+iosapic_startup_edge_irq (unsigned int irq)
+{
+	unmask_irq(irq);
+	/*
+	 * IOSAPIC simply drops interrupts pended while the
+	 * corresponding pin was masked, so we can't know if an
+	 * interrupt is pending already.  Let's hope not...
+	 */
+	return 0;
 }
 
 static void
-iosapic_disable_irq (unsigned int irq)
+iosapic_ack_edge_irq (unsigned int irq)
 {
-	int pin = iosapic_pin(irq);
-
-	if (pin < 0)
-		return;
-	disable_pin(pin, iosapic_addr(irq));
+	/*
+	 * Once we have recorded IRQ_PENDING already, we can mask the
+	 * interrupt for real. This prevents IRQ storms from unhandled
+	 * devices.
+	 */
+	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED))
+		mask_irq(irq);
 }
 
+#define iosapic_enable_edge_irq		unmask_irq
+#define iosapic_disable_edge_irq	nop
+#define iosapic_end_edge_irq		nop
+
+struct hw_interrupt_type irq_type_iosapic_edge = {
+	typename:	"IO-SAPIC-edge",
+	startup:	iosapic_startup_edge_irq,
+	shutdown:	iosapic_disable_edge_irq,
+	enable:		iosapic_enable_edge_irq,
+	disable:	iosapic_disable_edge_irq,
+	ack:		iosapic_ack_edge_irq,
+	end:		iosapic_end_edge_irq,
+	set_affinity:	iosapic_set_affinity
+};
+
 unsigned int
-iosapic_version(unsigned long base_addr) 
+iosapic_version (unsigned long base_addr) 
 {
 	/*
 	 * IOSAPIC Version Register return 32 bit structure like:
@@ -310,99 +215,19 @@
 	return readl(IO_SAPIC_WINDOW + base_addr);
 }
 
-static void
-iosapic_ack_irq (unsigned int irq)
-{
-}
-
-static void
-iosapic_end_irq (unsigned int irq)
-{
-	if (iosapic_trigger(irq) == IO_SAPIC_LEVEL)	/* ACK Level trigger interrupts */
-		writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI);
-}
-
-static void
-iosapic_set_affinity (unsigned int irq, unsigned long mask)
-{
-	printk("iosapic_set_affinity: not implemented yet\n");
-}
-
 void
 iosapic_init (unsigned long address)
 {
-	int	i;
-#ifdef CONFIG_IA64_IRQ_ACPI
+	struct hw_interrupt_type *irq_type;
 	struct pci_vector_struct *vectors;
-	int     irq;
-#else 
-	int     vector;
-#endif
+	int i, irq;
 
-	/*
-	 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
-	 * enabled.
-	 */
-	outb(0xff, 0xA1);
-	outb(0xff, 0x21);
-
-#if defined(CONFIG_IA64_SOFTSDV_HACKS)
-	memset(iosapic_vector, 0x0, sizeof(iosapic_vector));
-	for (i = 0; i < NR_IRQS; i++) {
-		iosapic_pin(i) = 0xff;
-		iosapic_addr(i) = (unsigned long) ioremap(address, 0);
-	}
-	/* XXX this should come from systab or some such: */
-# if 0
-	/* this doesn't look right --davidm 00/03/07 */
-	iosapic_pin(TIMER_IRQ) = 5;	/* System Clock Interrupt */
-# endif
-	iosapic_pin(0x40) = 3;	/* Keyboard */
-	iosapic_pin(0x92) = 9;	/* COM1 Serial Port */
-	iosapic_pin(0x80) = 4;	/* Periodic Interrupt */
-	iosapic_pin(0xc0) = 2;	/* Mouse */
-	iosapic_pin(0xe0) = 1;	/* IDE Disk */
-	iosapic_pin(0xf0) = 6;	/* E-IDE CDROM */
-	iosapic_pin(0xa0) = 10;	/* Real PCI Interrupt */
-#elif !defined(CONFIG_IA64_IRQ_ACPI)
-	/*
-	 * For systems where the routing info in ACPI is
-	 * unavailable/wrong, use the intr_routing information to
-	 * initialize the iosapic array
-	 */
-	i = -1;
-	while (intr_routing[++i].srcbus != 0xff) {
-		if (intr_routing[i].srcbus == BUS_ISA) {
-			vector = isa_irq_to_vector(intr_routing[i].srcbusirq);
-		} else if (intr_routing[i].srcbus == BUS_PCI) {
-			vector = intr_routing[i].iosapic_pin;
-		} else {
-			printk("unknown bus type %d for intr_routing[%d]\n",
-                               intr_routing[i].srcbus, i);
-			continue;
-		}
-		iosapic_pin(vector) = intr_routing[i].iosapic_pin;
-		iosapic_dmode(vector) = intr_routing[i].mode;
-		iosapic_polarity(vector) = intr_routing[i].polarity;
-		iosapic_trigger(vector) = intr_routing[i].trigger;
-# ifdef DEBUG_IRQ_ROUTING
-		printk("irq[0x%x(0x%x)]:0x%x, %d, %d, %d\n", vector, intr_routing[i].srcbusirq,
-		       iosapic_pin(vector), iosapic_dmode(vector), iosapic_polarity(vector),
-		       iosapic_trigger(vector));
-# endif
-	}
-#else /* !defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_IA64_IRQ_ACPI) */
 	/* 
-	 * Map the legacy ISA devices into the IOAPIC data; We'll override these
-	 * later with data from the ACPI Interrupt Source Override table.
-	 *
-	 * Huh, the Lion w/ FPSWA firmware has entries for _all_ of the legacy IRQs, 
-	 * including those that are not different from PC/AT standard.  I don't know
-	 * if this is a bug in the other firmware or not.  I'm going to leave this code 
-	 * here, so that this works on BigSur but will go ask Intel. --wfd 2000-Jan-19
-	 *
+	 * Map the legacy ISA devices into the IOSAPIC data.  Some of
+	 * these may get reprogrammed later on with data from the ACPI
+	 * Interrupt Source Override table.
 	 */
-	for (i =0 ; i < 16; i++) {
+	for (i = 0; i < 16; i++) {
 		irq = isa_irq_to_vector(i);
 		iosapic_pin(irq) = i; 
 		iosapic_bus(irq) = BUS_ISA;
@@ -445,41 +270,37 @@
 		       irq, iosapic_pin(irq));
 #endif
 	}
-#endif /* !CONFIG_IA64_IRQ_ACPI */
-}
 
-struct hw_interrupt_type irq_type_iosapic = {
-	typename:	"IOSAPIC",
-	startup:	iosapic_startup_irq,
-	shutdown:	iosapic_shutdown_irq,
-	enable:		iosapic_enable_irq,
-	disable:	iosapic_disable_irq,
-	ack:		iosapic_ack_irq,
-	end:		iosapic_end_irq,
-	set_affinity:	iosapic_set_affinity
-};
+	for (i = 0; i < NR_IRQS; ++i) {
+		if (iosapic_pin(i) != -1) {
+			if (iosapic_trigger(i) == IO_SAPIC_LEVEL)
+			  irq_type = &irq_type_iosapic_level;
+			else
+			  irq_type = &irq_type_iosapic_edge;
+			if (irq_desc[i].handler != &no_irq_type)
+				printk("dig_irq_init: warning: changing vector %d from %s to %s\n",
+				       i, irq_desc[i].handler->typename,
+				       irq_type->typename);
+			irq_desc[i].handler = irq_type;
+
+			/* program the IOSAPIC routing table: */
+			set_rte(iosapic_addr(i), iosapic_pin(i), iosapic_polarity(i),
+				iosapic_trigger(i), iosapic_dmode(i),
+				(ia64_get_lid() >> 16) & 0xffff, i);
+		}
+	}
+}
 
 void
 dig_irq_init (void)
 {
-	int i;
-
 	/*
-	 * Claim all non-legacy irq vectors as ours unless they're
-	 * claimed by someone else already (e.g., timer or IPI are
-	 * handled internally).
+	 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
+	 * enabled.
 	 */
-#if 0
-	for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) {
-		if (irq_desc[i].handler == &no_irq_type)
-			irq_desc[i].handler = &irq_type_iosapic;
-	}
-#else
-	for (i = 0; i <= IA64_MAX_VECTORED_IRQ; ++i) {
-		if (irq_desc[i].handler == &no_irq_type)
-			irq_desc[i].handler = &irq_type_iosapic;
-	}
-#endif
+	outb(0xff, 0xA1);
+	outb(0xff, 0x21);
+
 #ifndef CONFIG_IA64_DIG
 	iosapic_init(IO_SAPIC_DEFAULT_ADDR);
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/dig/setup.c linux/arch/ia64/dig/setup.c
--- v2.3.99-pre5/linux/arch/ia64/dig/setup.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/dig/setup.c	Fri Apr 21 15:21:23 2000
@@ -47,17 +47,11 @@
 	unsigned int orig_x, orig_y, num_cols, num_rows, font_height;
 
 	/*
-	 * This assumes that the EFI partition is physical disk 1
-	 * partition 1 and the Linux root disk is physical disk 1
-	 * partition 2.
+	 * Default to /dev/sda2.  This assumes that the EFI partition
+	 * is physical disk 1 partition 1 and the Linux root disk is
+	 * physical disk 1 partition 2.
 	 */
-#ifdef CONFIG_IA64_LION_HACKS
-	/* default to /dev/sda2 on Lion... */
 	ROOT_DEV = to_kdev_t(0x0802);		/* default to second partition on first drive */
-#else
-	/* default to /dev/dha2 on BigSur... */
-	ROOT_DEV = to_kdev_t(0x0302);		/* default to second partition on first drive */
-#endif
 
 #ifdef CONFIG_SMP
 	init_smp_config();
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/hp/Makefile linux/arch/ia64/hp/Makefile
--- v2.3.99-pre5/linux/arch/ia64/hp/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/hp/Makefile	Fri Apr 21 15:21:23 2000
@@ -10,7 +10,7 @@
 O_TARGET	= hp.a
 O_OBJS		= hpsim_console.o hpsim_irq.o hpsim_setup.o
 
-ifeq ($(CONFIG_IA64_GENERIC),y)
+ifdef CONFIG_IA64_GENERIC
 O_OBJS		+= hpsim_machvec.o
 endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/Makefile linux/arch/ia64/ia32/Makefile
--- v2.3.99-pre5/linux/arch/ia64/ia32/Makefile	Tue Apr 11 15:09:12 2000
+++ linux/arch/ia64/ia32/Makefile	Fri Apr 21 15:21:23 2000
@@ -10,7 +10,7 @@
 all: ia32.o
 
 O_TARGET := ia32.o
-O_OBJS	 := ia32_entry.o ia32_signal.o sys_ia32.o ia32_support.o binfmt_elf32.o
+O_OBJS	 := ia32_entry.o sys_ia32.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o
 
 clean::
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c
--- v2.3.99-pre5/linux/arch/ia64/ia32/binfmt_elf32.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/ia32/binfmt_elf32.c	Fri Apr 21 15:21:23 2000
@@ -134,6 +134,19 @@
 	regs->cr_ipsr &= ~IA64_PSR_AC;
 
 	regs->loadrs = 0;
+	/*
+	 *  According to the ABI %edx points to an `atexit' handler.
+	 *  Since we don't have one we'll set it to 0 and initialize
+	 *  all the other registers just to make things more deterministic,
+	 *  ala the i386 implementation.
+	 */
+	regs->r8 = 0;	/* %eax */
+	regs->r11 = 0;	/* %ebx */
+	regs->r9 = 0;	/* %ecx */
+	regs->r10 = 0;	/* %edx */
+	regs->r13 = 0;	/* %ebp */
+	regs->r14 = 0;	/* %esi */
+	regs->r15 = 0;	/* %edi */
 }
 
 #undef STACK_TOP
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S
--- v2.3.99-pre5/linux/arch/ia64/ia32/ia32_entry.S	Sat Feb 26 22:31:39 2000
+++ linux/arch/ia64/ia32/ia32_entry.S	Fri Apr 21 15:21:23 2000
@@ -1,14 +1,55 @@
 #include <asm/offsets.h>
 #include <asm/signal.h>
 
+	//
+	// Get possibly unaligned sigmask argument into an aligned
+	//   kernel buffer
+	.text
+	.proc ia32_rt_sigsuspend
+	.global ia32_rt_sigsuspend
+ia32_rt_sigsuspend:
+
+	// We'll cheat and not do an alloc here since we are ultimately
+	// going to do a simple branch to the IA64 sys_rt_sigsuspend.
+	// r32 is still the first argument which is the signal mask.
+	// We copy this 4-byte aligned value to an 8-byte aligned buffer
+	// in the task structure and then jump to the IA64 code.
+
+	mov r8=r0		// no memory access errors yet
+	add r10=4,r32
+	;;
+1:
+	ld4 r2=[r32]		// get first half of sigmask
+	ld4 r3=[r10]		// get second half of sigmask
+2:
+	cmp.lt p6,p0=r8,r0	// check memory access
+	;;
+(p6)	br.ret.sptk.many rp	//   it failed
+
+	adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13
+	adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13
+	;;
+	st4 [r32]=r2
+	st4 [r10]=r3
+	br.cond.sptk.many sys_rt_sigsuspend
+
+	.section __ex_table,"a"
+	data4 @gprel(1b)
+	data4 (2b-1b)|1
+	.previous
+
+
+	.endp ia32_rt_sigsuspend
+
 	.global ia32_ret_from_syscall
-	.proc ia64_ret_from_syscall
+	.proc ia32_ret_from_syscall
 ia32_ret_from_syscall:
 	cmp.ge p6,p7=r8,r0                      // syscall executed successfully?
 	adds r2=IA64_PT_REGS_R8_OFFSET+16,sp    // r2 = &pt_regs.r8
 	;; 
 	st8 [r2]=r8                             // store return value in slot for r8
 	br.cond.sptk.few ia64_leave_kernel
+	.endp ia32_ret_from_syscall
 
 	//
 	// Invoke a system call, but do some tracing before and after the call.
@@ -35,10 +76,21 @@
 	.endp ia32_trace_syscall
 
 	.align 16
+	.global sys32_vfork
+	.proc sys32_vfork
+sys32_vfork:
+	alloc r16=ar.pfs,2,2,3,0;;
+	mov out0=IA64_CLONE_VFORK|IA64_CLONE_VM|SIGCHLD	// out0 = clone_flags
+	br.cond.sptk.few .fork1			// do the work
+	.endp sys32_vfork
+
+	.align 16
 	.global sys32_fork
 	.proc sys32_fork
 sys32_fork:
 	alloc r16=ar.pfs,2,2,3,0;;
+	mov out0=SIGCHLD			// out0 = clone_flags
+.fork1:
 	movl r28=1f
 	mov loc1=rp
 	br.cond.sptk.many save_switch_stack
@@ -46,7 +98,6 @@
 	mov loc0=r16				// save ar.pfs across do_fork
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp
 	adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp
-	mov out0=SIGCHLD			// out0 = clone_flags
 	;;
 	ld8 out1=[r2]				// fetch usp from pt_regs.r12
 	br.call.sptk.few rp=do_fork
@@ -88,7 +139,7 @@
 	data8 sys_setuid
 	data8 sys_getuid
 	data8 sys_ni_syscall /* sys_stime is not supported on IA64 */  /* 25 */
-	data8 sys_ptrace
+	data8 sys32_ptrace
 	data8 sys32_alarm
 	data8 sys_ni_syscall
 	data8 sys_ni_syscall
@@ -105,7 +156,7 @@
 	data8 sys_rmdir		  /* 40 */
 	data8 sys_dup
 	data8 sys32_pipe
-	data8 sys_times
+	data8 sys32_times
 	data8 sys_ni_syscall	  /* old prof syscall holder */
 	data8 sys_brk		  /* 45 */
 	data8 sys_setgid
@@ -139,7 +190,7 @@
 	data8 sys_sethostname
 	data8 sys32_setrlimit	  /* 75 */
 	data8 sys32_getrlimit
-	data8 sys_getrusage
+	data8 sys32_getrusage
 	data8 sys32_gettimeofday
 	data8 sys32_settimeofday
 	data8 sys_getgroups	  /* 80 */
@@ -241,7 +292,7 @@
 	data8 sys_rt_sigpending
 	data8 sys_rt_sigtimedwait
 	data8 sys_rt_sigqueueinfo
-	data8 sys_rt_sigsuspend
+	data8 ia32_rt_sigsuspend
 	data8 sys_pread		  /* 180 */
 	data8 sys_pwrite
 	data8 sys_chown
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c
--- v2.3.99-pre5/linux/arch/ia64/ia32/ia32_signal.c	Sun Feb 13 19:29:03 2000
+++ linux/arch/ia64/ia32/ia32_signal.c	Fri Apr 21 15:21:23 2000
@@ -94,7 +94,9 @@
          err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
 
        /* non-iBCS2 extensions.. */
+#endif
        err |= __put_user(mask, &sc->oldmask);
+#if 0
        err |= __put_user(current->tss.cr2, &sc->cr2);
 #endif
        
@@ -196,7 +198,7 @@
        return (void *)((esp - frame_size) & -8ul);
 }
 
-static void
+static int
 setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set,
            struct pt_regs * regs) 
 {      
@@ -247,20 +249,21 @@
        regs->eflags &= ~TF_MASK;
 #endif
 
-#if 1
-       printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n",
-               current->comm, current->pid, frame, regs->cr_iip, frame->pretcode);
+#if 0
+       printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n",
+               current->comm, current->pid, sig, frame, regs->cr_iip, frame->pretcode);
 #endif
 
-       return;
+       return 1;
 
 give_sigsegv:
        if (sig == SIGSEGV)
                ka->sa.sa_handler = SIG_DFL;
        force_sig(SIGSEGV, current);
+       return 0;
 }
 
-static void
+static int
 setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info,
               sigset_t *set, struct pt_regs * regs)
 {
@@ -316,29 +319,29 @@
        regs->eflags &= ~TF_MASK;
 #endif
 
-#if 1
+#if 0
        printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n",
                current->comm, current->pid, frame, regs->cr_iip, frame->pretcode);
 #endif
 
-       return;
+       return 1;
 
 give_sigsegv:
        if (sig == SIGSEGV)
                ka->sa.sa_handler = SIG_DFL;
        force_sig(SIGSEGV, current);
+       return 0;
 }
 
-long
+int
 ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
 		   sigset_t *set, struct pt_regs *regs)
 {
        /* Set up the stack frame */
        if (ka->sa.sa_flags & SA_SIGINFO)
-               setup_rt_frame_ia32(sig, ka, info, set, regs);
+               return(setup_rt_frame_ia32(sig, ka, info, set, regs));
        else
-               setup_frame_ia32(sig, ka, set, regs);
-
+               return(setup_frame_ia32(sig, ka, set, regs));
 }
 
 asmlinkage int
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/ia32_traps.c linux/arch/ia64/ia32/ia32_traps.c
--- v2.3.99-pre5/linux/arch/ia64/ia32/ia32_traps.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/ia32/ia32_traps.c	Fri Apr 21 15:21:23 2000
@@ -0,0 +1,47 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/ia32.h>
+#include <asm/ptrace.h>
+
+int
+ia32_exception (struct pt_regs *regs, unsigned long isr)
+{
+	struct siginfo siginfo;
+
+	switch ((isr >> 16) & 0xff) {
+	      case 1:
+	      case 2:
+		if (isr == 0)
+			siginfo.si_code = TRAP_TRACE;
+		else if (isr & 0x4)
+			siginfo.si_code = TRAP_BRANCH;
+		else
+			siginfo.si_code = TRAP_BRKPT;
+		break;
+
+	      case 3:
+		siginfo.si_code = TRAP_BRKPT;
+		break;
+
+	      case 0:	/* Divide fault */
+	      case 4:	/* Overflow */
+	      case 5:	/* Bounds fault */
+	      case 6:	/* Invalid Op-code */
+	      case 7:	/* FP DNA */
+	      case 8:	/* Double Fault */
+	      case 9:	/* Invalid TSS */
+	      case 11:	/* Segment not present */
+	      case 12:	/* Stack fault */
+	      case 13:	/* General Protection Fault */
+	      case 16:	/* Pending FP error */
+	      case 17:	/* Alignment check */
+	      case 19:	/* SSE Numeric error */
+	      default:
+		return -1;
+	}
+	siginfo.si_signo = SIGTRAP;
+	siginfo.si_errno = 0;
+	send_sig_info(SIGTRAP, &siginfo, current);
+	return 0;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- v2.3.99-pre5/linux/arch/ia64/ia32/sys_ia32.c	Tue Apr 11 15:09:12 2000
+++ linux/arch/ia64/ia32/sys_ia32.c	Fri Apr 21 15:21:24 2000
@@ -58,32 +58,6 @@
 #define A(__x) ((unsigned long)(__x))
 #define AA(__x) ((unsigned long)(__x))
 
-/*
- * This is trivial, and on the face of it looks like it
- * could equally well be done in user mode.
- *
- * Not so, for quite unobvious reasons - register pressure.
- * In user mode vfork() cannot have a stack frame, and if
- * done by calling the "clone()" system call directly, you
- * do not have enough call-clobbered registers to hold all
- * the information you need.
- */
-asmlinkage int sys32_vfork(
-int dummy0,
-int dummy1,
-int dummy2,
-int dummy3,
-int dummy4,
-int dummy5,
-int dummy6,
-int dummy7,
-int stack)
-{
-	struct pt_regs *regs = (struct pt_regs *)&stack;
-
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r12, regs);
-}
-
 static int
 nargs(unsigned int arg, char **ap)
 {
@@ -842,82 +816,6 @@
 	return sys32_select(a.n, a.inp, a.outp, a.exp, a.tvp);
 }
 
-struct rusage32 {
-        struct timeval32 ru_utime;
-        struct timeval32 ru_stime;
-        int    ru_maxrss;
-        int    ru_ixrss;
-        int    ru_idrss;
-        int    ru_isrss;
-        int    ru_minflt;
-        int    ru_majflt;
-        int    ru_nswap;
-        int    ru_inblock;
-        int    ru_oublock;
-        int    ru_msgsnd; 
-        int    ru_msgrcv; 
-        int    ru_nsignals;
-        int    ru_nvcsw;
-        int    ru_nivcsw;
-};
-
-static int
-put_rusage (struct rusage32 *ru, struct rusage *r)
-{
-	int err;
-	
-	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
-	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
-	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
-	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
-	err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
-	err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
-	err |= __put_user (r->ru_idrss, &ru->ru_idrss);
-	err |= __put_user (r->ru_isrss, &ru->ru_isrss);
-	err |= __put_user (r->ru_minflt, &ru->ru_minflt);
-	err |= __put_user (r->ru_majflt, &ru->ru_majflt);
-	err |= __put_user (r->ru_nswap, &ru->ru_nswap);
-	err |= __put_user (r->ru_inblock, &ru->ru_inblock);
-	err |= __put_user (r->ru_oublock, &ru->ru_oublock);
-	err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
-	err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
-	err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
-	err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
-	err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
-	return err;
-}
-
-extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr,
-				int options, struct rusage * ru);
-
-asmlinkage int
-sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options,
-	    struct rusage32 *ru)
-{
-	if (!ru)
-		return sys_wait4(pid, stat_addr, options, NULL);
-	else {
-		struct rusage r;
-		int ret;
-		unsigned int status;
-		mm_segment_t old_fs = get_fs();
-		
-		set_fs (KERNEL_DS);
-		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
-		set_fs (old_fs);
-		if (put_rusage (ru, &r)) return -EFAULT;
-		if (stat_addr && put_user (status, stat_addr))
-			return -EFAULT;
-		return ret;
-	}
-}
-
-asmlinkage int
-sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options)
-{
-	return sys32_wait4(pid, stat_addr, options, NULL);
-}
-
 struct timespec32 {
 	int 	tv_sec;
 	int	tv_nsec;
@@ -1586,367 +1484,904 @@
 {
 	union semun fourth;
 	u32 pad;
-	int err = -EINVAL;
+	int err, err2;
+	struct semid64_ds s;
+	struct semid_ds32 *usp;
+	mm_segment_t old_fs;
 
 	if (!uptr)
-		goto out;
+		return -EINVAL;
 	err = -EFAULT;
 	if (get_user (pad, (u32 *)uptr))
-		goto out;
+		return err;
 	if(third == SETVAL)
 		fourth.val = (int)pad;
 	else
 		fourth.__pad = (void *)A(pad);
-	if (IPCOP_MASK (third) &
-	    (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) |
-	     IPCOP_MASK (GETVAL) | IPCOP_MASK (GETPID) |
-	     IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) |
-	     IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) |
-	     IPCOP_MASK (IPC_RMID))) {
+	switch (third) {
+
+	case IPC_INFO:
+	case IPC_RMID:
+	case IPC_SET:
+	case SEM_INFO:
+	case GETVAL:
+	case GETPID:
+	case GETNCNT:
+	case GETZCNT:
+	case GETALL:
+	case SETVAL:
+	case SETALL:
 		err = sys_semctl (first, second, third, fourth);
-	} else {
-		struct semid_ds s;
-		struct semid_ds32 *usp = (struct semid_ds32 *)A(pad);
-		mm_segment_t old_fs;
-		int need_back_translation;
-
-		if (third == IPC_SET) {
-			err = get_user (s.sem_perm.uid, &usp->sem_perm.uid);
-			err |= __get_user(s.sem_perm.gid, &usp->sem_perm.gid);
-			err |= __get_user(s.sem_perm.mode, &usp->sem_perm.mode);
-			if (err)
-				goto out;
-			fourth.__pad = &s;
-		}
-		need_back_translation =
-			(IPCOP_MASK (third) &
-			 (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0;
-		if (need_back_translation)
-			fourth.__pad = &s;
+		break;
+
+	case IPC_STAT:
+	case SEM_STAT:
+		usp = (struct semid_ds32 *)A(pad);
+		fourth.__pad = &s;
 		old_fs = get_fs ();
 		set_fs (KERNEL_DS);
 		err = sys_semctl (first, second, third, fourth);
 		set_fs (old_fs);
-		if (need_back_translation) {
-			int err2 = put_user(s.sem_perm.key, &usp->sem_perm.key);
-			err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid);
-			err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid);
-			err2 |= __put_user(s.sem_perm.cuid,
-					   &usp->sem_perm.cuid);
-			err2 |= __put_user (s.sem_perm.cgid,
-					    &usp->sem_perm.cgid);
-			err2 |= __put_user (s.sem_perm.mode,
-					    &usp->sem_perm.mode);
-			err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
-			err2 |= __put_user (s.sem_otime, &usp->sem_otime);
-			err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
-			err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
-			if (err2) err = -EFAULT;
-		}
+		err2 = put_user(s.sem_perm.key, &usp->sem_perm.key);
+		err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid);
+		err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid);
+		err2 |= __put_user(s.sem_perm.cuid,
+				   &usp->sem_perm.cuid);
+		err2 |= __put_user (s.sem_perm.cgid,
+				    &usp->sem_perm.cgid);
+		err2 |= __put_user (s.sem_perm.mode,
+				    &usp->sem_perm.mode);
+		err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
+		err2 |= __put_user (s.sem_otime, &usp->sem_otime);
+		err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
+		err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
+		if (err2)
+			err = -EFAULT;
+		break;
+
 	}
-out:
+
 	return err;
 }
 
 static int
 do_sys32_msgsnd (int first, int second, int third, void *uptr)
 {
-	struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf)
-				    + 4, GFP_USER);
-	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
-	mm_segment_t old_fs;
-	int err;
+	struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf)
+				    + 4, GFP_USER);
+	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+	mm_segment_t old_fs;
+	int err;
+
+	if (!p)
+		return -ENOMEM;
+	err = get_user (p->mtype, &up->mtype);
+	err |= __copy_from_user (p->mtext, &up->mtext, second);
+	if (err)
+		goto out;
+	old_fs = get_fs ();
+	set_fs (KERNEL_DS);
+	err = sys_msgsnd (first, p, second, third);
+	set_fs (old_fs);
+out:
+	kfree (p);
+	return err;
+}
+
+static int
+do_sys32_msgrcv (int first, int second, int msgtyp, int third,
+		 int version, void *uptr)
+{
+	struct msgbuf32 *up;
+	struct msgbuf *p;
+	mm_segment_t old_fs;
+	int err;
+
+	if (!version) {
+		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
+		struct ipc_kludge ipck;
+
+		err = -EINVAL;
+		if (!uptr)
+			goto out;
+		err = -EFAULT;
+		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge)))
+			goto out;
+		uptr = (void *)A(ipck.msgp);
+		msgtyp = ipck.msgtyp;
+	}
+	err = -ENOMEM;
+	p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+	if (!p)
+		goto out;
+	old_fs = get_fs ();
+	set_fs (KERNEL_DS);
+	err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+	set_fs (old_fs);
+	if (err < 0)
+		goto free_then_out;
+	up = (struct msgbuf32 *)uptr;
+	if (put_user (p->mtype, &up->mtype) ||
+	    __copy_to_user (&up->mtext, p->mtext, err))
+		err = -EFAULT;
+free_then_out:
+	kfree (p);
+out:
+	return err;
+}
+
+static int
+do_sys32_msgctl (int first, int second, void *uptr)
+{
+	int err, err2;
+	struct msqid_ds m;
+	struct msqid64_ds m64;
+	struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+	mm_segment_t old_fs;
+
+	switch (second) {
+
+	case IPC_INFO:
+	case IPC_RMID:
+	case MSG_INFO:
+		err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
+		break;
+
+	case IPC_SET:
+		err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
+		err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
+		err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
+		err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
+		if (err)
+			break;
+		old_fs = get_fs ();
+		set_fs (KERNEL_DS);
+		err = sys_msgctl (first, second, &m);
+		set_fs (old_fs);
+		break;
+
+	case IPC_STAT:
+	case MSG_STAT:
+		old_fs = get_fs ();
+		set_fs (KERNEL_DS);
+		err = sys_msgctl (first, second, &m64);
+		set_fs (old_fs);
+		err2 = put_user (m64.msg_perm.key, &up->msg_perm.key);
+		err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid);
+		err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid);
+		err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid);
+		err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid);
+		err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode);
+		err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq);
+		err2 |= __put_user(m64.msg_stime, &up->msg_stime);
+		err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
+		err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
+		err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes);
+		err2 |= __put_user(m64.msg_qnum, &up->msg_qnum);
+		err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes);
+		err2 |= __put_user(m64.msg_lspid, &up->msg_lspid);
+		err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid);
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	}
+
+	return err;
+}
+
+static int
+do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+{
+	unsigned long raddr;
+	u32 *uaddr = (u32 *)A((u32)third);
+	int err = -EINVAL;
+
+	if (version == 1)
+		return err;
+	err = sys_shmat (first, uptr, second, &raddr);
+	if (err)
+		return err;
+	err = put_user (raddr, uaddr);
+	return err;
+}
+
+static int
+do_sys32_shmctl (int first, int second, void *uptr)
+{
+	int err = -EFAULT, err2;
+	struct shmid_ds s;
+	struct shmid64_ds s64;
+	struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
+	mm_segment_t old_fs;
+	struct shm_info32 {
+		int used_ids;
+		u32 shm_tot, shm_rss, shm_swp;
+		u32 swap_attempts, swap_successes;
+	} *uip = (struct shm_info32 *)uptr;
+	struct shm_info si;
+
+	switch (second) {
+
+	case IPC_INFO:
+	case IPC_RMID:
+	case SHM_LOCK:
+	case SHM_UNLOCK:
+		err = sys_shmctl (first, second, (struct shmid_ds *)uptr);
+		break;
+	case IPC_SET:
+		err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
+		err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
+		err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
+		if (err)
+			break;
+		old_fs = get_fs ();
+		set_fs (KERNEL_DS);
+		err = sys_shmctl (first, second, &s);
+		set_fs (old_fs);
+		break;
+
+	case IPC_STAT:
+	case SHM_STAT:
+		old_fs = get_fs ();
+		set_fs (KERNEL_DS);
+		err = sys_shmctl (first, second, &s64);
+		set_fs (old_fs);
+		if (err < 0)
+			break;
+		err2 = put_user (s64.shm_perm.key, &up->shm_perm.key);
+		err2 |= __put_user (s64.shm_perm.uid, &up->shm_perm.uid);
+		err2 |= __put_user (s64.shm_perm.gid, &up->shm_perm.gid);
+		err2 |= __put_user (s64.shm_perm.cuid,
+				    &up->shm_perm.cuid);
+		err2 |= __put_user (s64.shm_perm.cgid,
+				    &up->shm_perm.cgid);
+		err2 |= __put_user (s64.shm_perm.mode,
+				    &up->shm_perm.mode);
+		err2 |= __put_user (s64.shm_perm.seq, &up->shm_perm.seq);
+		err2 |= __put_user (s64.shm_atime, &up->shm_atime);
+		err2 |= __put_user (s64.shm_dtime, &up->shm_dtime);
+		err2 |= __put_user (s64.shm_ctime, &up->shm_ctime);
+		err2 |= __put_user (s64.shm_segsz, &up->shm_segsz);
+		err2 |= __put_user (s64.shm_nattch, &up->shm_nattch);
+		err2 |= __put_user (s64.shm_cpid, &up->shm_cpid);
+		err2 |= __put_user (s64.shm_lpid, &up->shm_lpid);
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	case SHM_INFO:
+		old_fs = get_fs ();
+		set_fs (KERNEL_DS);
+		err = sys_shmctl (first, second, &si);
+		set_fs (old_fs);
+		if (err < 0)
+			break;
+		err2 = put_user (si.used_ids, &uip->used_ids);
+		err2 |= __put_user (si.shm_tot, &uip->shm_tot);
+		err2 |= __put_user (si.shm_rss, &uip->shm_rss);
+		err2 |= __put_user (si.shm_swp, &uip->shm_swp);
+		err2 |= __put_user (si.swap_attempts,
+				    &uip->swap_attempts);
+		err2 |= __put_user (si.swap_successes,
+				    &uip->swap_successes);
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	}
+	return err;
+}
+
+asmlinkage int
+sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+{
+	int version, err;
+
+	lock_kernel();
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+
+	case SEMOP:
+		/* struct sembuf is the same on 32 and 64bit :)) */
+		err = sys_semop (first, (struct sembuf *)AA(ptr),
+				 second);
+		break;
+	case SEMGET:
+		err = sys_semget (first, second, third);
+		break;
+	case SEMCTL:
+		err = do_sys32_semctl (first, second, third,
+				       (void *)AA(ptr));
+		break;
+
+	case MSGSND:
+		err = do_sys32_msgsnd (first, second, third,
+				       (void *)AA(ptr));
+		break;
+	case MSGRCV:
+		err = do_sys32_msgrcv (first, second, fifth, third,
+				       version, (void *)AA(ptr));
+		break;
+	case MSGGET:
+		err = sys_msgget ((key_t) first, second);
+		break;
+	case MSGCTL:
+		err = do_sys32_msgctl (first, second, (void *)AA(ptr));
+		break;
+
+	case SHMAT:
+		err = do_sys32_shmat (first, second, third,
+				      version, (void *)AA(ptr));
+		break;
+	case SHMDT: 
+		err = sys_shmdt ((char *)AA(ptr));
+		break;
+	case SHMGET:
+		err = sys_shmget (first, second, third);
+		break;
+	case SHMCTL:
+		err = do_sys32_shmctl (first, second, (void *)AA(ptr));
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	unlock_kernel();
+	return err;
+}
+
+/*
+ * sys_time() can be implemented in user-level using
+ * sys_gettimeofday().  IA64 did this but i386 Linux did not
+ * so we have to implement this system call here.
+ */
+asmlinkage long sys32_time(int * tloc)
+{
+	int i;
+
+	/* SMP: This is fairly trivial. We grab CURRENT_TIME and 
+	   stuff it to user space. No side effects */
+	i = CURRENT_TIME;
+	if (tloc) {
+		if (put_user(i,tloc))
+			i = -EFAULT;
+	}
+	return i;
+}
+
+struct rusage32 {
+        struct timeval32 ru_utime;
+        struct timeval32 ru_stime;
+        int    ru_maxrss;
+        int    ru_ixrss;
+        int    ru_idrss;
+        int    ru_isrss;
+        int    ru_minflt;
+        int    ru_majflt;
+        int    ru_nswap;
+        int    ru_inblock;
+        int    ru_oublock;
+        int    ru_msgsnd; 
+        int    ru_msgrcv; 
+        int    ru_nsignals;
+        int    ru_nvcsw;
+        int    ru_nivcsw;
+};
+
+static int
+put_rusage (struct rusage32 *ru, struct rusage *r)
+{
+	int err;
+	
+	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
+	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
+	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
+	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
+	err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
+	err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
+	err |= __put_user (r->ru_idrss, &ru->ru_idrss);
+	err |= __put_user (r->ru_isrss, &ru->ru_isrss);
+	err |= __put_user (r->ru_minflt, &ru->ru_minflt);
+	err |= __put_user (r->ru_majflt, &ru->ru_majflt);
+	err |= __put_user (r->ru_nswap, &ru->ru_nswap);
+	err |= __put_user (r->ru_inblock, &ru->ru_inblock);
+	err |= __put_user (r->ru_oublock, &ru->ru_oublock);
+	err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
+	err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
+	err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
+	err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
+	err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
+	return err;
+}
+
+extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr,
+				int options, struct rusage * ru);
+
+asmlinkage int
+sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options,
+	    struct rusage32 *ru)
+{
+	if (!ru)
+		return sys_wait4(pid, stat_addr, options, NULL);
+	else {
+		struct rusage r;
+		int ret;
+		unsigned int status;
+		mm_segment_t old_fs = get_fs();
+		
+		set_fs (KERNEL_DS);
+		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
+		set_fs (old_fs);
+		if (put_rusage (ru, &r)) return -EFAULT;
+		if (stat_addr && put_user (status, stat_addr))
+			return -EFAULT;
+		return ret;
+	}
+}
+
+asmlinkage int
+sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options)
+{
+	return sys32_wait4(pid, stat_addr, options, NULL);
+}
+
+
+extern asmlinkage int
+sys_getrusage(int who, struct rusage *ru);
+
+asmlinkage int
+sys32_getrusage(int who, struct rusage32 *ru)
+{
+	struct rusage r;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_getrusage(who, &r);
+	set_fs (old_fs);
+	if (put_rusage (ru, &r)) return -EFAULT;
+	return ret;
+}
+
+struct tms32 {
+	__kernel_clock_t32 tms_utime;
+	__kernel_clock_t32 tms_stime;
+	__kernel_clock_t32 tms_cutime;
+	__kernel_clock_t32 tms_cstime;
+};
+                                
+extern asmlinkage long sys_times(struct tms * tbuf);
+
+asmlinkage long
+sys32_times(struct tms32 *tbuf)
+{
+	struct tms t;
+	long ret;
+	mm_segment_t old_fs = get_fs ();
+	int err;
+	
+	set_fs (KERNEL_DS);
+	ret = sys_times(tbuf ? &t : NULL);
+	set_fs (old_fs);
+	if (tbuf) {
+		err = put_user (t.tms_utime, &tbuf->tms_utime);
+		err |= __put_user (t.tms_stime, &tbuf->tms_stime);
+		err |= __put_user (t.tms_cutime, &tbuf->tms_cutime);
+		err |= __put_user (t.tms_cstime, &tbuf->tms_cstime);
+		if (err)
+			ret = -EFAULT;
+	}
+	return ret;
+}
+
+unsigned int
+ia32_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int *val)
+{
+	size_t copied;
+	unsigned int ret;
+
+	copied = access_process_vm(child, addr, val, sizeof(*val), 0);
+	return(copied != sizeof(ret) ? -EIO : 0);
+}
+
+unsigned int
+ia32_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int val)
+{
+
+	if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val))
+		return -EIO;
+	return 0;
+}
+
+/*
+ *  The order in which registers are stored in the ptrace regs structure
+ */
+#define PT_EBX	0
+#define PT_ECX	1
+#define PT_EDX	2
+#define PT_ESI	3
+#define PT_EDI	4
+#define PT_EBP	5
+#define PT_EAX	6
+#define PT_DS	7
+#define PT_ES	8
+#define PT_FS	9
+#define PT_GS	10
+#define PT_ORIG_EAX 11
+#define PT_EIP	12
+#define PT_CS 	13
+#define PT_EFL	14
+#define PT_UESP	15
+#define PT_SS	16
+
+unsigned int
+getreg(struct task_struct *child, int regno)
+{
+	struct pt_regs *child_regs;
+
+	child_regs = ia64_task_regs(child);
+	switch (regno / sizeof(int)) {
+
+	case PT_EBX:
+		return(child_regs->r11);
+	case PT_ECX:
+		return(child_regs->r9);
+	case PT_EDX:
+		return(child_regs->r10);
+	case PT_ESI:
+		return(child_regs->r14);
+	case PT_EDI:
+		return(child_regs->r15);
+	case PT_EBP:
+		return(child_regs->r13);
+	case PT_EAX:
+	case PT_ORIG_EAX:
+		return(child_regs->r8);
+	case PT_EIP:
+		return(child_regs->cr_iip);
+	case PT_UESP:
+		return(child_regs->r12);
+	case PT_EFL:
+		return(child->thread.eflag);
+	case PT_DS:
+	case PT_ES:
+	case PT_FS:
+	case PT_GS:
+	case PT_SS:
+		return((unsigned int)__USER_DS);
+	case PT_CS:
+		return((unsigned int)__USER_CS);
+	default:
+		printk("getregs:unknown register %d\n", regno);
+		break;
+
+	}
+	return(0);
+}
+
+void
+putreg(struct task_struct *child, int regno, unsigned int value)
+{
+	struct pt_regs *child_regs;
+
+	child_regs = ia64_task_regs(child);
+	switch (regno / sizeof(int)) {
+
+	case PT_EBX:
+		child_regs->r11 = value;
+		break;
+	case PT_ECX:
+		child_regs->r9 = value;
+		break;
+	case PT_EDX:
+		child_regs->r10 = value;
+		break;
+	case PT_ESI:
+		child_regs->r14 = value;
+		break;
+	case PT_EDI:
+		child_regs->r15 = value;
+		break;
+	case PT_EBP:
+		child_regs->r13 = value;
+		break;
+	case PT_EAX:
+	case PT_ORIG_EAX:
+		child_regs->r8 = value;
+		break;
+	case PT_EIP:
+		child_regs->cr_iip = value;
+		break;
+	case PT_UESP:
+		child_regs->r12 = value;
+		break;
+	case PT_EFL:
+		child->thread.eflag = value;
+		break;
+	case PT_DS:
+	case PT_ES:
+	case PT_FS:
+	case PT_GS:
+	case PT_SS:
+		if (value != __USER_DS)
+			printk("setregs:try to set invalid segment register %d = %x\n", regno, value);
+		break;
+	case PT_CS:
+		if (value != __USER_CS)
+			printk("setregs:try to set invalid segment register %d = %x\n", regno, value);
+		break;
+	default:
+		printk("getregs:unknown register %d\n", regno);
+		break;
+
+	}
+}
+
+static inline void
+ia32f2ia64f(void *dst, void *src)
+{
+
+	__asm__ ("ldfe f6=[%1] ;;\n\t"
+		 "stf.spill [%0]=f6"
+		:
+		: "r"(dst), "r"(src));
+	return;
+}
+
+static inline void
+ia64f2ia32f(void *dst, void *src)
+{
 
-	if (!p)
-		return -ENOMEM;
-	err = get_user (p->mtype, &up->mtype);
-	err |= __copy_from_user (p->mtext, &up->mtext, second);
-	if (err)
-		goto out;
-	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
-	err = sys_msgsnd (first, p, second, third);
-	set_fs (old_fs);
-out:
-	kfree (p);
-	return err;
+	__asm__ ("ldf.fill f6=[%1] ;;\n\t"
+		 "stfe [%0]=f6"
+		:
+		: "r"(dst),  "r"(src));
+	return;
 }
 
-static int
-do_sys32_msgrcv (int first, int second, int msgtyp, int third,
-		 int version, void *uptr)
+void
+put_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos)
 {
-	struct msgbuf32 *up;
-	struct msgbuf *p;
-	mm_segment_t old_fs;
-	int err;
+	struct _fpreg_ia32 *f;
+	char buf[32];
 
-	if (!version) {
-		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
-		struct ipc_kludge ipck;
+	f = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+	if ((regno += tos) >= 8)
+		regno -= 8;
+	switch (regno) {
+
+	case 0:
+		ia64f2ia32f(f, &ptp->f8);
+		break;
+	case 1:
+		ia64f2ia32f(f, &ptp->f9);
+		break;
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		ia64f2ia32f(f, &swp->f10 + (regno - 2));
+		break;
 
-		err = -EINVAL;
-		if (!uptr)
-			goto out;
-		err = -EFAULT;
-		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge)))
-			goto out;
-		uptr = (void *)A(ipck.msgp);
-		msgtyp = ipck.msgtyp;
 	}
-	err = -ENOMEM;
-	p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
-	if (!p)
-		goto out;
-	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
-	err = sys_msgrcv (first, p, second + 4, msgtyp, third);
-	set_fs (old_fs);
-	if (err < 0)
-		goto free_then_out;
-	up = (struct msgbuf32 *)uptr;
-	if (put_user (p->mtype, &up->mtype) ||
-	    __copy_to_user (&up->mtext, p->mtext, err))
-		err = -EFAULT;
-free_then_out:
-	kfree (p);
-out:
-	return err;
+	__copy_to_user(reg, f, sizeof(*reg));
+	return;
 }
 
-static int
-do_sys32_msgctl (int first, int second, void *uptr)
+void
+get_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos)
 {
-	int err;
 
-	if (IPCOP_MASK (second) &
-	    (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) |
-	     IPCOP_MASK (IPC_RMID))) {
-		err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
-	} else {
-		struct msqid_ds m;
-		struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
-		mm_segment_t old_fs;
-
-		if (second == IPC_SET) {
-			err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
-			err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
-			err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
-			err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
-			if (err)
-				goto out;
-		}
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_msgctl (first, second, &m);
-		set_fs (old_fs);
-		if (IPCOP_MASK (second) &
-		    (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) {
-			int err2 = put_user (m.msg_perm.key, &up->msg_perm.key);
-			err2 |= __put_user(m.msg_perm.uid, &up->msg_perm.uid);
-			err2 |= __put_user(m.msg_perm.gid, &up->msg_perm.gid);
-			err2 |= __put_user(m.msg_perm.cuid, &up->msg_perm.cuid);
-			err2 |= __put_user(m.msg_perm.cgid, &up->msg_perm.cgid);
-			err2 |= __put_user(m.msg_perm.mode, &up->msg_perm.mode);
-			err2 |= __put_user(m.msg_perm.seq, &up->msg_perm.seq);
-			err2 |= __put_user(m.msg_stime, &up->msg_stime);
-			err2 |= __put_user(m.msg_rtime, &up->msg_rtime);
-			err2 |= __put_user(m.msg_ctime, &up->msg_ctime);
-			err2 |= __put_user(m.msg_cbytes, &up->msg_cbytes);
-			err2 |= __put_user(m.msg_qnum, &up->msg_qnum);
-			err2 |= __put_user(m.msg_qbytes, &up->msg_qbytes);
-			err2 |= __put_user(m.msg_lspid, &up->msg_lspid);
-			err2 |= __put_user(m.msg_lrpid, &up->msg_lrpid);
-			if (err2)
-				err = -EFAULT;
-		}
-	}
+	if ((regno += tos) >= 8)
+		regno -= 8;
+	switch (regno) {
 
-out:
-	return err;
+	case 0:
+		__copy_from_user(&ptp->f8, reg, sizeof(*reg));
+		break;
+	case 1:
+		__copy_from_user(&ptp->f9, reg, sizeof(*reg));
+		break;
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		__copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg));
+		break;
+
+	}
+	return;
 }
 
-static int
-do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+int
+save_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save)
 {
-	unsigned long raddr;
-	u32 *uaddr = (u32 *)A((u32)third);
-	int err = -EINVAL;
-
-	if (version == 1)
-		goto out;
-	err = sys_shmat (first, uptr, second, &raddr);
-	if (err)
-		goto out;
-	err = put_user (raddr, uaddr);
-out:
-	return err;
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return(-EIO);
+	__put_user(tsk->thread.fcr, &save->cw);
+	__put_user(tsk->thread.fsr, &save->sw);
+	__put_user(tsk->thread.fsr >> 32, &save->tag);
+	__put_user(tsk->thread.fir, &save->ipoff);
+	__put_user(__USER_CS, &save->cssel);
+	__put_user(tsk->thread.fdr, &save->dataoff);
+	__put_user(__USER_DS, &save->datasel);
+	/*
+	 *  Stack frames start with 16-bytes of temp space
+	 */
+	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+	ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 3;
+	for (i = 0; i < 8; i++)
+		put_fpreg(i, &save->_st[i], ptp, swp, tos);
+	return(0);
 }
 
-static int
-do_sys32_shmctl (int first, int second, void *uptr)
+int
+restore_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save)
 {
-	int err;
-
-	if (IPCOP_MASK (second) &
-	    (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK)
-	     | IPCOP_MASK (SHM_UNLOCK) | IPCOP_MASK (IPC_RMID))) {
-		err = sys_shmctl (first, second, (struct shmid_ds *)uptr);
-	} else {
-		struct shmid_ds s;
-		struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
-		mm_segment_t old_fs;
-
-		if (second == IPC_SET) {
-			err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
-			err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
-			err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
-			if (err)
-				goto out;
-		}
-		old_fs = get_fs ();
-		set_fs (KERNEL_DS);
-		err = sys_shmctl (first, second, &s);
-		set_fs (old_fs);
-		if (err < 0)
-			goto out;
-
-		/* Mask it even in this case so it becomes a CSE. */
-		if (second == SHM_INFO) {
-			struct shm_info32 {
-				int used_ids;
-				u32 shm_tot, shm_rss, shm_swp;
-				u32 swap_attempts, swap_successes;
-			} *uip = (struct shm_info32 *)uptr;
-			struct shm_info *kp = (struct shm_info *)&s;
-			int err2 = put_user (kp->used_ids, &uip->used_ids);
-			err2 |= __put_user (kp->shm_tot, &uip->shm_tot);
-			err2 |= __put_user (kp->shm_rss, &uip->shm_rss);
-			err2 |= __put_user (kp->shm_swp, &uip->shm_swp);
-			err2 |= __put_user (kp->swap_attempts,
-					    &uip->swap_attempts);
-			err2 |= __put_user (kp->swap_successes,
-					    &uip->swap_successes);
-			if (err2)
-				err = -EFAULT;
-		} else if (IPCOP_MASK (second) &
-			   (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) {
-			int err2 = put_user (s.shm_perm.key, &up->shm_perm.key);
-			err2 |= __put_user (s.shm_perm.uid, &up->shm_perm.uid);
-			err2 |= __put_user (s.shm_perm.gid, &up->shm_perm.gid);
-			err2 |= __put_user (s.shm_perm.cuid,
-					    &up->shm_perm.cuid);
-			err2 |= __put_user (s.shm_perm.cgid,
-					    &up->shm_perm.cgid);
-			err2 |= __put_user (s.shm_perm.mode,
-					    &up->shm_perm.mode);
-			err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq);
-			err2 |= __put_user (s.shm_atime, &up->shm_atime);
-			err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
-			err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
-			err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
-			err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
-			err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
-			err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
-			if (err2)
-				err = -EFAULT;
-		}
-	}
-out:
-	return err;
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	int fsrlo, fsrhi;
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EIO);
+	__get_user(tsk->thread.fcr, (unsigned int *)&save->cw);
+	__get_user(fsrlo, (unsigned int *)&save->sw);
+	__get_user(fsrhi, (unsigned int *)&save->tag);
+	tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo;
+	__get_user(tsk->thread.fir, (unsigned int *)&save->ipoff);
+	__get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff);
+	/*
+	 *  Stack frames start with 16-bytes of temp space
+	 */
+	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+	ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 3;
+	for (i = 0; i < 8; i++)
+		get_fpreg(i, &save->_st[i], ptp, swp, tos);
+	return(0);
 }
 
-asmlinkage int
-sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long);
+
+/*
+ *  Note that the IA32 version of `ptrace' calls the IA64 routine for
+ *    many of the requests.  This will only work for requests that do
+ *    not need access to the calling processes `pt_regs' which is located
+ *    at the address of `stack'.  Once we call the IA64 `sys_ptrace' then
+ *    the address of `stack' will not be the address of the `pt_regs'.
+ */
+asmlinkage long
+sys32_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
+	    long arg4, long arg5, long arg6, long arg7, long stack)
 {
-	int version, err;
+	struct pt_regs *regs = (struct pt_regs *) &stack;
+	struct task_struct *child;
+	long i, ret;
+	unsigned int value;
 
 	lock_kernel();
-	version = call >> 16; /* hack for backward compatibility */
-	call &= 0xffff;
+	if (request == PTRACE_TRACEME) {
+		ret = sys_ptrace(request, pid, addr, data,
+				arg4, arg5, arg6, arg7, stack);
+		goto out;
+	}
 
-	if (call <= SEMCTL)
-		switch (call) {
-		case SEMOP:
-			/* struct sembuf is the same on 32 and 64bit :)) */
-			err = sys_semop (first, (struct sembuf *)AA(ptr),
-					 second);
-			goto out;
-		case SEMGET:
-			err = sys_semget (first, second, third);
-			goto out;
-		case SEMCTL:
-			err = do_sys32_semctl (first, second, third,
-					       (void *)AA(ptr));
-			goto out;
-		default:
-			err = -EINVAL;
-			goto out;
-		};
-	if (call <= MSGCTL) 
-		switch (call) {
-		case MSGSND:
-			err = do_sys32_msgsnd (first, second, third,
-					       (void *)AA(ptr));
-			goto out;
-		case MSGRCV:
-			err = do_sys32_msgrcv (first, second, fifth, third,
-					       version, (void *)AA(ptr));
-			goto out;
-		case MSGGET:
-			err = sys_msgget ((key_t) first, second);
-			goto out;
-		case MSGCTL:
-			err = do_sys32_msgctl (first, second, (void *)AA(ptr));
-			goto out;
-		default:
-			err = -EINVAL;
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+	ret = -EPERM;
+	if (pid == 1)		/* no messing around with init! */
+		goto out;
+
+	if (request == PTRACE_ATTACH) {
+		ret = sys_ptrace(request, pid, addr, data,
+				arg4, arg5, arg6, arg7, stack);
+		goto out;
+	}
+	ret = -ESRCH;
+	if (!(child->flags & PF_PTRACED))
+		goto out;
+	if (child->state != TASK_STOPPED) {
+		if (request != PTRACE_KILL)
 			goto out;
+	}
+	if (child->p_pptr != current)
+		goto out;
+
+	switch (request) {
+	      case PTRACE_PEEKTEXT:
+	      case PTRACE_PEEKDATA:	/* read word at location addr */
+		ret = ia32_peek(regs, child, addr, &value);
+		if (ret == 0)
+			ret = put_user(value, (unsigned int *)data);
+		else
+			ret = -EIO;
+		goto out;
+
+	      case PTRACE_POKETEXT:
+	      case PTRACE_POKEDATA:	/* write the word at location addr */
+		ret = ia32_poke(regs, child, addr, (unsigned int)data);
+		goto out;
+
+	      case PTRACE_PEEKUSR:	/* read word at addr in USER area */
+		ret = 0;
+		break;
+
+	      case PTRACE_POKEUSR:	/* write word at addr in USER area */
+		ret = 0;
+		break;
+
+	      case IA32_PTRACE_GETREGS:
+	  	if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) {
+			ret = -EIO;
+			break;
 		}
-	if (call <= SHMCTL) 
-		switch (call) {
-		case SHMAT:
-			err = do_sys32_shmat (first, second, third,
-					      version, (void *)AA(ptr));
-			goto out;
-		case SHMDT: 
-			err = sys_shmdt ((char *)AA(ptr));
-			goto out;
-		case SHMGET:
-			err = sys_shmget (first, second, third);
-			goto out;
-		case SHMCTL:
-			err = do_sys32_shmctl (first, second, (void *)AA(ptr));
-			goto out;
-		default:
-			err = -EINVAL;
-			goto out;
+		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
+			__put_user(getreg(child, i),(unsigned int *) data);
+			data += sizeof(int);
 		}
+		ret = 0;
+		break;
 
-	err = -EINVAL;
+	      case IA32_PTRACE_SETREGS:
+	      {
+		unsigned int tmp;
+	  	if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
+			__get_user(tmp, (unsigned int *) data);
+			putreg(child, i, tmp);
+			data += sizeof(int);
+		}
+		ret = 0;
+		break;
+	      }
 
-out:
-	unlock_kernel();
-	return err;
-}
+	      case IA32_PTRACE_GETFPREGS:
+		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
+		break;
 
-/*
- * sys_time() can be implemented in user-level using
- * sys_gettimeofday().  IA64 did this but i386 Linux did not
- * so we have to implement this system call here.
- */
-asmlinkage long sys32_time(int * tloc)
-{
-	int i;
+	      case IA32_PTRACE_SETFPREGS:
+		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
+		break;
+
+	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
+	      case PTRACE_CONT:		/* restart after signal. */
+	      case PTRACE_KILL:
+	      case PTRACE_SINGLESTEP:	/* execute chile for one instruction */
+	      case PTRACE_DETACH:	/* detach a process */
+		unlock_kernel();
+		ret = sys_ptrace(request, pid, addr, data,
+				arg4, arg5, arg6, arg7, stack);
+		return(ret);
+
+	      default:
+		ret = -EIO;
+		break;
 
-	/* SMP: This is fairly trivial. We grab CURRENT_TIME and 
-	   stuff it to user space. No side effects */
-	i = CURRENT_TIME;
-	if (tloc) {
-		if (put_user(i,tloc))
-			i = -EFAULT;
 	}
-	return i;
+  out:
+	unlock_kernel();
+	return ret;
 }
 
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
@@ -2719,37 +3154,6 @@
 	return ret;
 }
 
-struct tms32 {
-	__kernel_clock_t32 tms_utime;
-	__kernel_clock_t32 tms_stime;
-	__kernel_clock_t32 tms_cutime;
-	__kernel_clock_t32 tms_cstime;
-};
-                                
-extern asmlinkage long sys_times(struct tms * tbuf);
-
-asmlinkage long
-sys32_times(struct tms32 *tbuf)
-{
-	struct tms t;
-	long ret;
-	mm_segment_t old_fs = get_fs ();
-	int err;
-	
-	set_fs (KERNEL_DS);
-	ret = sys_times(tbuf ? &t : NULL);
-	set_fs (old_fs);
-	if (tbuf) {
-		err = put_user (t.tms_utime, &tbuf->tms_utime);
-		err |= __put_user (t.tms_stime, &tbuf->tms_stime);
-		err |= __put_user (t.tms_cutime, &tbuf->tms_cutime);
-		err |= __put_user (t.tms_cstime, &tbuf->tms_cstime);
-		if (err)
-			ret = -EFAULT;
-	}
-	return ret;
-}
-
 extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
 
 asmlinkage int
@@ -2789,23 +3193,6 @@
 	return ret;
 }
 
-extern asmlinkage int
-sys_getrusage(int who, struct rusage *ru);
-
-asmlinkage int
-sys32_getrusage(int who, struct rusage32 *ru)
-{
-	struct rusage r;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-		
-	set_fs (KERNEL_DS);
-	ret = sys_getrusage(who, &r);
-	set_fs (old_fs);
-	if (put_rusage (ru, &r)) return -EFAULT;
-	return ret;
-}
-
 
 /* XXX These as well... */
 extern __inline__ struct socket *
@@ -4355,4 +4742,3 @@
 	return ret;
 }
 #endif	// NOTYET
-
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/Makefile linux/arch/ia64/kdb/Makefile
--- v2.3.99-pre5/linux/arch/ia64/kdb/Makefile	Tue Apr 11 15:09:12 2000
+++ linux/arch/ia64/kdb/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,21 +0,0 @@
-#
-# Makefile for ia64-specific kdb files..
-#
-#  Copyright 1999, Silicon Graphics Inc.
-#
-#  Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
-#  Code for IA64 written by Goutham Rao <goutham.rao@intel.com> and
-#  Sreenivas Subramoney <sreenivas.subramoney@intel.com>
-#
-
-SUB_DIRS     :=
-MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
-.S.o:
-	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
-
-L_TARGET = kdb.a
-L_OBJS  = kdbsupport.o kdb_io.o kdb_bt.o kdb_traps.o
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdb_bt.c linux/arch/ia64/kdb/kdb_bt.c
--- v2.3.99-pre5/linux/arch/ia64/kdb/kdb_bt.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kdb/kdb_bt.c	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-/**
- * Minimalist Kernel Debugger 
- * Machine dependent stack traceback code for IA-64.
- *
- * Copyright (C) 1999 Goutham Rao <goutham.rao@intel.com>
- * Copyright (C) 1999 Sreenivas Subramoney <sreenivas.subramoney@intel.com>
- * Intel Corporation, August 1999.
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 99/12/03 D. Mosberger	Reimplemented based on <asm-ia64/unwind.h> API.
- * 99/12/06 D. Mosberger	Added support for backtracing other processes.
- */
-
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kdb.h>
-#include <asm/system.h>
-#include <asm/current.h>
-#include <asm/kdbsupport.h>
-
-/*
- * Minimal stack back trace functionality.
- */
-int
-kdb_bt (int argc, const char **argv, const char **envp, struct pt_regs *regs)
-{
-	struct task_struct *task = current;
-	struct ia64_frame_info info;
-	char *name;
-	int diag;
-
-	if (strcmp(argv[0], "btp") == 0) {
-		unsigned long pid;
-
-		diag = kdbgetularg(argv[1], &pid);
-		if (diag)
-			return diag;
-
-		task = find_task_by_pid(pid);
-		if (!task) {
-			kdb_printf("No process with pid == %d found\n", pid);
-			return 0;
-		}
-		regs = ia64_task_regs(task);
-	} else if (argc) {
-		kdb_printf("bt <address> is unsupported for IA-64\n");
-		return 0;
-	}
-
-	if (task == current) {
-		/*
-		 * Upon entering kdb, the stack frame looks like this:
-		 *
-		 *	+---------------------+
-		 *	|   struct pt_regs    |
-		 *	+---------------------+
-		 *	|		      |
-		 *	|   kernel stack      |
-		 *	|		      |
-		 *	+=====================+ <--- top of stack upon entering kdb
-		 *	|   struct pt_regs    |
-		 *	+---------------------+
-		 *	| struct switch_stack |
-		 *	+---------------------+
-		 */
-		if (user_mode(regs)) {
-			/* We are not implementing stack backtrace from user mode code */
-			kdb_printf ("Not in Kernel\n");
-			return 0;
-		}
-		ia64_unwind_init_from_current(&info, regs);
-	} else {
-		/*
-		 * For a blocked task, the stack frame looks like this:
-		 *
-		 *	+---------------------+
-		 *	|   struct pt_regs    |
-		 *	+---------------------+
-		 *	|		      |
-		 *	|   kernel stack      |
-		 *	|		      |
-		 *	+---------------------+
-		 *	| struct switch_stack |
-		 *	+=====================+ <--- task->thread.ksp
-		 */
-		ia64_unwind_init_from_blocked_task(&info, task);
-	}
-
-	kdb_printf("Ret Address           Reg Stack base       Name\n\n") ;
-	do {
-		unsigned long ip = ia64_unwind_get_ip(&info);
-
-		name = kdbnearsym(ip);
-		if (!name) {
-			kdb_printf("Interrupt\n");
-			return 0;
-		}
-		kdb_printf("0x%016lx: [0x%016lx] %s\n", ip, ia64_unwind_get_bsp(&info), name);
-	} while (ia64_unwind_to_previous_frame(&info) >= 0);
-	return 0;
-}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdb_io.c linux/arch/ia64/kdb/kdb_io.c
--- v2.3.99-pre5/linux/arch/ia64/kdb/kdb_io.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kdb/kdb_io.c	Wed Dec 31 16:00:00 1969
@@ -1,350 +0,0 @@
-/*
- * Kernel Debugger Console I/O handler
- *
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
- * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
- * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
- *
- * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
- *
- * Modifications from:
- *	Chuck Fleckenstein		1999/07/20
- *		Move kdb_info struct declaration to this file
- *		for cases where serial support is not compiled into
- *		the kernel.
- *
- *	Masahiro Adegawa		1999/07/20
- *		Handle some peculiarities of japanese 86/106
- *		keyboards.
- *
- *	marc@mucom.co.il		1999/07/20
- *		Catch buffer overflow for serial input.
- *
- *      Scott Foehner  
- *              Port to ia64
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/serial_reg.h>
-#include <linux/spinlock.h>
-
-#include <asm/io.h>
-
-#include "pc_keyb.h"
-
-int kdb_port = 0;
-
-/*
- * This module contains code to read characters from the keyboard or a serial
- * port.
- * 
- * It is used by the kernel debugger, and is polled, not interrupt driven.
- *
- */
-
-/*
- * send:  Send a byte to the keyboard controller.  Used primarily to 
- * 	  alter LED settings.
- */
-
-static void
-kdb_kbdsend(unsigned char byte) 
-{
-	while (inb(KBD_STATUS_REG) & KBD_STAT_IBF)
-		;
-	outb(KBD_DATA_REG, byte);
-}
-
-static void
-kdb_kbdsetled(int leds)
-{
-	kdb_kbdsend(KBD_CMD_SET_LEDS);
-	kdb_kbdsend((unsigned char)leds);
-}
-
-static void
-console_read (char *buffer, size_t bufsize)
-{
-	struct console *in;
-	struct console *out;
-	char *cp, ch;
-
-	for (in = console_drivers; in; in = in->next) {
-		if ((in->flags & CON_ENABLED) && (in->read || in->wait_key))
-			break;
-	}
-	for (out = console_drivers; out; out = out->next) {
-		if ((out->flags & CON_ENABLED) && out->write)
-			break;
-	}
-
-	if ((!in->read && !in->wait_key) || !out->write) {
-		panic("kdb_io: can't do console i/o!");
-	}
-
-	if (in->read) {
-		/* this is untested... */
-		(*in->read)(in, buffer, bufsize);
-		return;
-	}
-
-	bufsize -= 2;			/* leave room for CR & NUL terminator */
-	cp = buffer;
-	while (1) {
-		ch = (*in->wait_key)(in);
-		switch (ch) {
-		      case '\b':
-			if (cp > buffer) {
-				--cp, ++bufsize;
-				(*out->write)(out, "\b \b", 3);
-			}
-			break;
-
-		      case '\025':
-			while (cp > buffer) {
-				--cp, ++bufsize;
-				(*out->write)(out, "\b \b", 3);
-			}
-			break;
-
-		      case '\r':
-		      case '\n':
-			(*out->write)(out, "\r\n", 2);
-			*cp++ = '\n';
-			*cp++ = '\0';
-			return;
-
-		      default:
-			if (bufsize > 0) {
-				(*out->write)(out, &ch, 1);
-				--bufsize;
-				*cp++ = ch;
-			}
-			break;
-		}
-	}
-}
-
-char *
-kdb_getscancode(char *buffer, size_t bufsize)
-{
-	/*
-	 * XXX Shouldn't kdb _always_ use console based I/O?  That's what the console
-	 * abstraction is for, after all... ---davidm
-	 */
-#ifdef CONFIG_IA64_HP_SIM
-	extern spinlock_t console_lock;
-	unsigned long flags;
-
-	spin_lock_irqsave(&console_lock, flags);
-	console_read(buffer, bufsize);
-	spin_unlock_irqrestore(&console_lock, flags);
-	return buffer;
-#else /* !CONFIG_IA64_HP_SIM */
-	char	*cp = buffer;
-	int	scancode, scanstatus;
-	static int shift_lock = 0;	/* CAPS LOCK state (0-off, 1-on) */
-	static int shift_key  = 0;	/* Shift next keypress */
-	static int ctrl_key   = 0;
-	static int leds       = 2;	/* Num lock */
-	u_short keychar;
-	extern u_short plain_map[], shift_map[], ctrl_map[];
-
-	bufsize -= 2;	/* Reserve space for newline and null byte */
-
-	/*
-	 * If we came in via a serial console, we allow that to
-	 * be the input window for kdb.
-	 */
-	if (kdb_port != 0) {
-		char ch;
-		int status;
-#define serial_inp(info, offset) inb((info) + (offset))
-#define serial_out(info, offset, v) outb((v), (info) + (offset))
-
-		while(1) {
-			while ((status = serial_inp(kdb_port, UART_LSR)) 
-							& UART_LSR_DR) {
-readchar:
-				ch = serial_inp(kdb_port, UART_RX);
-				if (ch == 8) {		/* BS */
-					if (cp > buffer) {
-						--cp, bufsize++;
-						printk("%c %c", 0x08, 0x08);
-					}
-					continue;
-				}
-				serial_out(kdb_port, UART_TX, ch);
-				if (ch == 13) {		/* CR */
-					*cp++ = '\n';
-					*cp++ = '\0';
-					serial_out(kdb_port, UART_TX, 10);
-					return(buffer);
-				}
-				/*
-				 * Discard excess characters
-				 */
-				if (bufsize > 0) {
-					*cp++ = ch;
-					bufsize--;
-				} 
-			}
-			while (((status = serial_inp(kdb_port, UART_LSR)) 
-					& UART_LSR_DR) == 0);
-		}
-	}
-
-	while (1) {
-
-		/*
-		 * Wait for a valid scancode
-		 */
-
-		while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
-			;
-
-		/*
-		 * Fetch the scancode
-		 */
-		scancode = inb(KBD_DATA_REG);
-		scanstatus = inb(KBD_STATUS_REG);
-
-		/*
-		 * Ignore mouse events.
-		 */
-		if (scanstatus & KBD_STAT_MOUSE_OBF)
-			continue;
-
-		/*
-		 * Ignore release, trigger on make
-		 * (except for shift keys, where we want to 
-		 *  keep the shift state so long as the key is
-		 *  held down).
-		 */
-
-		if (((scancode&0x7f) == 0x2a) 
-		 || ((scancode&0x7f) == 0x36)) {
-			/*
-			 * Next key may use shift table
-			 */
-			if ((scancode & 0x80) == 0) {
-				shift_key=1;
-			} else {
-				shift_key=0;
-			}
-			continue;
-		}
-
-		if ((scancode&0x7f) == 0x1d) {
-			/*
-			 * Left ctrl key
-			 */
-			if ((scancode & 0x80) == 0) {
-				ctrl_key = 1;
-			} else {
-				ctrl_key = 0;
-			}
-			continue;
-		}
-
-		if ((scancode & 0x80) != 0) 
-			continue;
-
-		scancode &= 0x7f;
-
-		/*
-	 	 * Translate scancode
-		 */
-		
-		if (scancode == 0x3a) {
-			/*
-			 * Toggle caps lock
-			 */
-			shift_lock ^= 1;
-			leds ^= 0x4;	/* toggle caps lock led */
-			
-			kdb_kbdsetled(leds);
-			continue;
-		}
-			
-		if (scancode == 0x0e) {
-			/*
-			 * Backspace
-			 */
-			if (cp > buffer) {
-				--cp, bufsize++;
-
-				/*
-				 * XXX - erase character on screen
-				 */
-				printk("%c %c", 0x08, 0x08);
-			}
-			continue;
-		}
-	
-		if (scancode == 0xe0) {
-			continue;
-		}
-
-		/*
-		 * For Japanese 86/106 keyboards 
-		 * 	See comment in drivers/char/pc_keyb.c.
-		 * 	- Masahiro Adegawa
-		 */
-		if (scancode == 0x73) {
-			scancode = 0x59;
-		} else if (scancode == 0x7d) {
-			scancode = 0x7c;
-		}
-			
-		if (!shift_lock && !shift_key) {
-			keychar = plain_map[scancode];
-		} else if (shift_lock || shift_key) {
-			keychar = shift_map[scancode];
-		} else if (ctrl_key) {
-			keychar = ctrl_map[scancode];
-		} else {
-			keychar = 0x0020;
-			printk("Unknown state/scancode (%d)\n", scancode);
-		}
-		 
-		if ((scancode & 0x7f) == 0x1c) {
-			/*
-			 * enter key.  All done.
-			 */
-			printk("\n");
-			break;
-		}
-
-		/*
-		 * echo the character.
-		 */
-		printk("%c", keychar&0xff);
-
-		if (bufsize) {
-			--bufsize;
-			*cp++ = keychar&0xff;
-		} else {
-			printk("buffer overflow\n");
-			break;
-		}
-
-	}
-
-	*cp++ = '\n';		/* White space for parser */
-	*cp++ = '\0';		/* String termination */
-
-#if defined(NOTNOW)
-	cp = buffer;
-	while (*cp) {
-		printk("char 0x%x\n", *cp++);
-	}
-#endif
-
-	return buffer;
-#endif /* !CONFIG_IA64_HP_SIM */
-}
-
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdb_traps.c linux/arch/ia64/kdb/kdb_traps.c
--- v2.3.99-pre5/linux/arch/ia64/kdb/kdb_traps.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kdb/kdb_traps.c	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/kdb.h>
-
-static struct kdb_bp_support {
-	unsigned long	addr ;
-	int		slot ;
-} kdb_bp_info[NR_CPUS] ;
-
-
-extern void kdb_bp_install (void);
-
-/*
- * This gets invoked right before a call to ia64_fault().
- * Returns zero the normal fault handler should be invoked.
- */
-long
-ia64_kdb_fault_handler (unsigned long vector, unsigned long isr, unsigned long ifa,
-			unsigned long iim, unsigned long itir, unsigned long arg5,
-			unsigned long arg6, unsigned long arg7, unsigned long stack)
-{
-	struct switch_stack *sw = (struct switch_stack *) &stack;
-	struct pt_regs *regs = (struct pt_regs *) (sw + 1);
-	int bundle_slot;
-
-	/*
-	 * TBD
-	 * If KDB is configured, enter KDB for any fault.
-	 */
-	if ((vector == 29) || (vector == 35) || (vector == 36)) {
-		if (!user_mode(regs)) {
-			bundle_slot = ia64_psr(regs)->ri;
-			if (vector == 29) {
-				if (bundle_slot == 0) {
-			 		kdb_bp_info[0].addr = regs->cr_iip;
-					kdb_bp_info[0].slot = bundle_slot;
-					kdb(KDB_REASON_FLTDBG, 0, regs);
-				} else {
-					if ((bundle_slot < 3) &&
-					    (kdb_bp_info[0].addr == regs->cr_iip))
-					{
-						ia64_psr(regs)->id = 1;
-						ia64_psr(regs)->db = 1;
-						kdb_bp_install() ;
-					} else /* some error ?? */
-						kdb(KDB_REASON_FLTDBG, 0, regs);
-				}
-			} else /* single step or taken branch */
-				kdb(KDB_REASON_DEBUG, 0, regs);
-			return 1;
-		}
-	}
-	return 0;
-}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdbsupport.c linux/arch/ia64/kdb/kdbsupport.c
--- v2.3.99-pre5/linux/arch/ia64/kdb/kdbsupport.c	Sat Feb 26 22:31:39 2000
+++ linux/arch/ia64/kdb/kdbsupport.c	Wed Dec 31 16:00:00 1969
@@ -1,1329 +0,0 @@
-/*
- * Minimalist Kernel Debugger
- *
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
- * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
- * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
- * Copyright (C) David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
- *
- * Modifications from:
- *      Richard Bass                    1999/07/20
- *              Many bug fixes and enhancements.
- *      Scott Foehner
- *              Port to ia64
- *      Srinivasa Thirumalachar
- *              RSE support for ia64
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/kdb.h>
-#include <linux/stddef.h> 
-#include <linux/vmalloc.h>
-
-#include <asm/delay.h>
-#include <asm/kdbsupport.h>
-#include <asm/rse.h>
-#include <asm/uaccess.h>
-
-extern kdb_state_t kdb_state ;
-k_machreg_t dbregs[KDB_DBREGS];
-
-static int __init
-kdb_setup (char *str)
-{
-	kdb_flags |= KDB_FLAG_EARLYKDB;
-	return 1;
-}
-
-__setup("kdb", kdb_setup);
-
-static int
-kdb_ia64_itm (int argc, const char **argv, const char **envp, struct pt_regs *regs)
-{
-	int diag;
-	unsigned long val;
-
-	diag = kdbgetularg(argv[1], &val);
-	if (diag)
-		return diag;
-	kdb_printf("new itm=%0xlx\n", val);
-
-	ia64_set_itm(val);
-	return 0;
-}
-
-static int
-kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *regs)
-{
-	u64 lid, tpr, lrr0, lrr1, itv, pmv, cmcv;
-
-	asm ("mov %0=cr.lid" : "=r"(lid));
-	asm ("mov %0=cr.tpr" : "=r"(tpr));
-	asm ("mov %0=cr.lrr0" : "=r"(lrr0));
-	asm ("mov %0=cr.lrr1" : "=r"(lrr1));
-	printk("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1);
-
-	asm ("mov %0=cr.itv" : "=r"(itv));
-	asm ("mov %0=cr.pmv" : "=r"(pmv));
-	asm ("mov %0=cr.cmcv" : "=r"(cmcv));
-	printk("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv);
-
-	printk("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n",
-		ia64_get_irr0(), ia64_get_irr1(), ia64_get_irr2(), ia64_get_irr3());
-
-	printk("itc=0x%016lx, itm=0x%016lx\n", ia64_get_itc(), ia64_get_itm());
-	return 0;
-}
-
-void __init
-kdb_init (void)
-{
-	extern void kdb_inittab(void);
-	unsigned long reg;
-
-	kdb_inittab();
-	kdb_initbptab();
-#if 0
-	kdb_disinit();
-#endif
-	kdb_printf("kdb version %d.%d by Scott Lurndal. "\
-		   "Copyright SGI, All Rights Reserved\n",
-		   KDB_MAJOR_VERSION, KDB_MINOR_VERSION);
-
-	/* Enable debug registers */
-        __asm__ ("mov %0=psr":"=r"(reg));
-        reg |= IA64_PSR_DB;
-        __asm__ ("mov psr.l=%0"::"r"(reg));
-        ia64_srlz_d();
-
-	/* Init kdb state */
-	kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ;
-
-	kdb_register("irr", kdb_ia64_sir, "", "Show interrupt registers", 0);
-	kdb_register("itm", kdb_ia64_itm, "", "Set new ITM value", 0);
-}
-
-/*
- * kdbprintf
- * kdbgetword
- * kdb_getstr
- */
-
-char *
-kbd_getstr(char *buffer, size_t bufsize, char *prompt)
-{
-	extern char* kdb_getscancode(char *, size_t);
-
-#if defined(CONFIG_SMP)
-	kdb_printf(prompt, smp_processor_id());
-#else
-	kdb_printf("%s", prompt);
-#endif
-
-	return kdb_getscancode(buffer, bufsize);
-
-}
-
-int
-kdb_printf(const char *fmt, ...)
-{
-	char buffer[256];
-	va_list	ap;
-	int diag;
-	int linecount;
-
-	diag = kdbgetintenv("LINES", &linecount);
-	if (diag) 
-		linecount = 22;
-
-	va_start(ap, fmt);
-	vsprintf(buffer, fmt, ap);
-	va_end(ap);
-
-	printk("%s", buffer);
-#if 0
-	if (strchr(buffer, '\n') != NULL) {
-		kdb_nextline++;
-	}
-
-	if (kdb_nextline == linecount) {
-		char buf1[16];
-		char buf2[32];
-		extern char* kdb_getscancode(char *, size_t);
-		char *moreprompt;
-
-		/*
-		 * Pause until cr.
-		 */
-		moreprompt = kdbgetenv("MOREPROMPT");
-		if (moreprompt == NULL) {
-			moreprompt = "more> ";
-		}
-
-#if defined(CONFIG_SMP)
-		if (strchr(moreprompt, '%')) {
-			sprintf(buf2, moreprompt, smp_processor_id());
-			moreprompt = buf2;
-		}
-#endif
-
-		printk(moreprompt);
-		(void) kdb_getscancode(buf1, sizeof(buf1));
-
-		kdb_nextline = 1;
-
-		if ((buf1[0] == 'q') 
-		 || (buf1[0] == 'Q')) {
-			kdb_longjmp(&kdbjmpbuf, 1);
-		}
-	}
-#endif	
-	return 0;
-}
-
-unsigned long
-kdbgetword(unsigned long addr, int width)
-{
-	/*
-	 * This function checks the address for validity.  Any address
-	 * in the range PAGE_OFFSET to high_memory is legal, any address
-	 * which maps to a vmalloc region is legal, and any address which
-	 * is a user address, we use get_user() to verify validity.
-	 */
-
-	if (addr < PAGE_OFFSET) {
-		/*
-		 * Usermode address.
-		 */
-		unsigned long diag;
-		unsigned long ulval;
-
-		switch (width) {
-	        case 8:
-		{	unsigned long *lp;
-
-			lp = (unsigned long *) addr;
-			diag = get_user(ulval, lp);
-			break;
-		}
-		case 4:
-		{	unsigned int *ip;
-
-			ip = (unsigned int *) addr;
-			diag = get_user(ulval, ip);
-			break;
-		}
-		case 2:
-		{	unsigned short *sp;
-
-			sp = (unsigned short *) addr;
-			diag = get_user(ulval, sp);
-			break;
-		}
-		case 1:
-		{	unsigned char *cp;
-
-			cp = (unsigned char *) addr;
-			diag = get_user(ulval, cp);
-			break;
-		}
-		default:
-			printk("kdbgetword: Bad width\n");
-			return 0L;
-		}
-			
-		if (diag) {
-			if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) {
-				printk("kdb: Bad user address 0x%lx\n", addr);
-				kdb_flags |= KDB_FLAG_SUPRESS;
-			}
-			return 0L;
-		}
-		kdb_flags &= ~KDB_FLAG_SUPRESS;
-		return ulval;
-	}
-
-	if (addr > (unsigned long)high_memory) {
-		extern int kdb_vmlist_check(unsigned long, unsigned long);
-
-		if (!kdb_vmlist_check(addr, addr+width)) {
-			/*
-			 * Would appear to be an illegal kernel address; 
-			 * Print a message once, and don't print again until
-			 * a legal address is used.
-			 */
-			if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) {
-				printk("kdb: Bad kernel address 0x%lx\n", addr);
-				kdb_flags |= KDB_FLAG_SUPRESS;
-			}
-			return 0L;
-		}
-	}
-
-	/*
-	 * A good address.  Reset error flag.
-	 */
-	kdb_flags &= ~KDB_FLAG_SUPRESS;
-
-	switch (width) {
-	case 8:
-	{	unsigned long *lp;
-
-		lp = (unsigned long *)(addr);
-		return *lp;
-	}
-	case 4:
-	{	unsigned int *ip;
-
-		ip = (unsigned int *)(addr);
-		return *ip;
-	}
-	case 2:
-	{	unsigned short *sp;
-
-		sp = (unsigned short *)(addr);
-		return *sp;
-	}
-	case 1:
-	{	unsigned char *cp;
-
-		cp = (unsigned char *)(addr);
-		return *cp;
-	}
-	}
-
-	printk("kdbgetword: Bad width\n");
-	return 0L;
-}
-
-/*
- * Start of breakpoint management routines
- */
-
-/*
- * Arg: bp structure
- */
-
-int
-kdb_allocdbreg(kdb_bp_t *bp)
-{
-	int i=0;
-
-	/* For inst bkpt, just return. No hw reg alloc to be done. */
-
-	if (bp->bp_mode == BKPTMODE_INST) {
-		return i;
-	} else if (bp->bp_mode == BKPTMODE_DATAW) {
-		for(i=0; i<KDB_DBREGS; i++) {
-			if (dbregs[i] == 0xffffffff) {
-				dbregs[i] = 0;
-				return i;
-			}
-		}
-	}
-
-	return -1;
-}
-
-void
-kdb_freedbreg(kdb_bp_t *bp)
-{
-	if (bp->bp_mode == BKPTMODE_DATAW)
-		dbregs[bp->bp_reg] = 0xffffffff;
-}
-
-void
-kdb_initdbregs(void)
-{
-	int i;
-
-	for(i=0; i<KDB_DBREGS; i++) {
-		dbregs[i] = 0xffffffff;
-	}
-}
-int
-kdbinstalltrap(int type, handler_t newh, handler_t *oldh)
-{
-	/*
-	 * Usurp INTn.  XXX - TBD.
-	 */
-
-	return 0;
-}
-
-int
-install_instbkpt(kdb_bp_t *bp)
-{
-	unsigned long	*addr = (unsigned long *)bp->bp_addr ;
-	bundle_t	*bundle = (bundle_t *)bp->bp_longinst;
-
-	/* save current bundle */
-	*bundle = *(bundle_t *)addr ;
-
-	/* Set the break point! */
-	((bundle_t *)addr)->lform.low8 = (
-		(((bundle_t *)addr)->lform.low8 & ~INST_SLOT0_MASK) |
-		BREAK_INSTR);
-
-	/* set flag */
-	bp->bp_instvalid = 1 ;
-
-	/* flush icache as it is stale now */
-	ia64_flush_icache_page((unsigned long)addr) ;
-
-#ifdef KDB_DEBUG
-	kdb_printf ("[0x%016lx]: install 0x%016lx with 0x%016lx\n",
-		    addr, bundle->lform.low8, addr[0]) ;
-#endif
-	return 0 ;
-}
-
-int
-install_databkpt(kdb_bp_t *bp)
-{
-	unsigned long dbreg_addr = bp->bp_reg * 2;
-	unsigned long dbreg_cond = dbreg_addr + 1;
-	unsigned long value = 0x8fffffffffffffff;
-	unsigned long addr = (unsigned long)bp->bp_addr;
-	__asm__ ("mov dbr[%0]=%1"::"r"(dbreg_cond),"r"(value));
-//	__asm__ ("movl %0,%%db0\n\t"::"r"(contents));
-	__asm__ ("mov dbr[%0]=%1"::"r"(dbreg_addr),"r"(addr));
-	ia64_insn_group_barrier();
-	ia64_srlz_i();
-	ia64_insn_group_barrier();
-
-#ifdef KDB_DEBUG
-	kdb_printf("installed dbkpt at 0x%016lx\n", addr) ;
-#endif
-	return 0;
-}
-
-int
-kdbinstalldbreg(kdb_bp_t *bp)
-{
-	if (bp->bp_mode == BKPTMODE_INST) {
-		return install_instbkpt(bp) ;
-	} else if (bp->bp_mode == BKPTMODE_DATAW) {
-		return install_databkpt(bp) ;
-	}
-	return 0;
-}
-
-void
-remove_instbkpt(kdb_bp_t *bp)
-{
-	unsigned long   *addr = (unsigned long *)bp->bp_addr ;
-	bundle_t        *bundle = (bundle_t *)bp->bp_longinst;
-
-	if (!bp->bp_instvalid)
-	/* Nothing to remove. If we just alloced the bkpt
-	 * but never resumed, the bp_inst will not be valid. */
-		return ;
-
-#ifdef KDB_DEBUG
-	kdb_printf ("[0x%016lx]: remove 0x%016lx with 0x%016lx\n", 
-		    addr, addr[0], bundle->lform.low8) ;
-#endif
-
-	/* restore current bundle */
-	*(bundle_t *)addr = *bundle ;
-	/* reset the flag */
-	bp->bp_instvalid = 0 ;
-	ia64_flush_icache_page((unsigned long)addr) ;
-}
-  
-void
-remove_databkpt(kdb_bp_t *bp)
-{
-	int		regnum = bp->bp_reg ;
-	unsigned long dbreg_addr = regnum * 2;
-	unsigned long dbreg_cond = dbreg_addr + 1;
-	unsigned long value = 0x0fffffffffffffff;
-	__asm__ ("mov dbr[%0]=%1"::"r"(dbreg_cond),"r"(value));
-//	__asm__ ("movl %0,%%db0\n\t"::"r"(contents));
-	ia64_insn_group_barrier();
-	ia64_srlz_i();
-	ia64_insn_group_barrier();
-
-#ifdef KDB_DEBUG
-	kdb_printf("removed dbkpt at 0x%016lx\n", bp->bp_addr) ;
-#endif
-}
-
-void
-kdbremovedbreg(kdb_bp_t *bp)
-{
-	if (bp->bp_mode == BKPTMODE_INST) {
-		remove_instbkpt(bp) ;
-	} else if (bp->bp_mode == BKPTMODE_DATAW) {
-		remove_databkpt(bp) ;
-	}
-}
-
-k_machreg_t
-kdb_getdr6(void)
-{
-	return kdb_getdr(6);
-}
-
-k_machreg_t
-kdb_getdr7(void)
-{
-	return kdb_getdr(7);
-}
-
-k_machreg_t
-kdb_getdr(int regnum)
-{
-	k_machreg_t contents = 0;
-	unsigned long reg = (unsigned long)regnum;
-
-	__asm__ ("mov %0=ibr[%1]"::"r"(contents),"r"(reg));
-//        __asm__ ("mov ibr[%0]=%1"::"r"(dbreg_cond),"r"(value));	
-
-	return contents;
-}
-
-
-k_machreg_t
-kdb_getcr(int regnum)
-{
-	k_machreg_t contents = 0;
-	return contents;
-}
-
-void
-kdb_putdr6(k_machreg_t contents)
-{
-	kdb_putdr(6, contents);
-}
-
-void
-kdb_putdr7(k_machreg_t contents)
-{
-	kdb_putdr(7, contents);
-}
-
-void
-kdb_putdr(int regnum, k_machreg_t contents)
-{
-}
-
-void
-get_fault_regs(fault_regs_t *fr)
-{
-	fr->ifa = 0 ;
-	fr->isr = 0 ;
-
-	__asm__ ("rsm psr.ic;;") ;
-        ia64_srlz_d();
-        __asm__ ("mov %0=cr.ifa" : "=r"(fr->ifa));
-        __asm__ ("mov %0=cr.isr" : "=r"(fr->isr));
-	__asm__ ("ssm psr.ic;;") ;
-        ia64_srlz_d();
-}
-
-/*
- * kdb_db_trap
- *
- * 	Perform breakpoint processing upon entry to the
- *	processor debugger fault.   Determine and print
- *	the active breakpoint.
- *
- * Parameters:
- *	ef	Exception frame containing machine register state
- *	reason	Why did we enter kdb - fault or break
- * Outputs:
- *	None.
- * Returns:
- *	0	Standard instruction or data breakpoint encountered
- *	1	Single Step fault ('ss' command)
- *	2	Single Step fault, caller should continue ('ssb' command)
- * Locking:
- *	None.
- * Remarks:
- *	Yup, there be goto's here.
- */
-
-int
-kdb_db_trap(struct pt_regs *ef, int reason)
-{
-	int i, rv=0;
-
-	/* Trying very hard to not change the interface to kdb.
-	 * So, eventhough we have these values in the fault function
-	 * it is not passed in but read again.
-	 */
-	fault_regs_t	faultregs ;
-
-	if (reason == KDB_REASON_FLTDBG)
-		get_fault_regs(&faultregs) ;
-
-	/* NOTE : XXX: This has to be done only for data bkpts */
-	/* Prevent it from continuously faulting */
-	ef->cr_ipsr |= 0x0000002000000000;
-
-	if (ef->cr_ipsr & 0x0000010000000000) {
-		/* single step */
-		ef->cr_ipsr &= 0xfffffeffffffffff;
-		if ((kdb_state.bkpt_handling_state == BKPTSTATE_HANDLED) 
-			&& (kdb_state.cmd_given == CMDGIVEN_GO)) 
-				; 
-		else
-			kdb_printf("SS trap at 0x%lx\n", ef->cr_iip + ia64_psr(ef)->ri);
-		rv = 1;
-		kdb_state.reason_for_entry = ENTRYREASON_SSTEP ;
-		goto handled;
-	} else
-		kdb_state.reason_for_entry = ENTRYREASON_GO ;
-
-        /*
-         * Determine which breakpoint was encountered.
-         */
-        for(i=0; i<KDB_MAXBPT; i++) {
-                if ((breakpoints[i].bp_enabled)
-                 && ((breakpoints[i].bp_addr == ef->cr_iip) ||
-			((faultregs.ifa) && 
-			 (breakpoints[i].bp_addr == faultregs.ifa)))) {
-                        /*
-                         * Hit this breakpoint.  Remove it while we are
-                         * handling hit to avoid recursion. XXX ??
-                         */
-			if (breakpoints[i].bp_addr == faultregs.ifa)
-                        	kdb_printf("Data breakpoint #%d for 0x%lx at 0x%lx\n",
-                                  i, breakpoints[i].bp_addr, ef->cr_iip + ia64_psr(ef)->ri);
-			else
-                        	kdb_printf("%s breakpoint #%d at 0x%lx\n",
-                                  	rwtypes[0],
-                                  	i, breakpoints[i].bp_addr);
-
-                        /*
-                         * For an instruction breakpoint, disassemble
-                         * the current instruction.
-                         */
-#if 0
-                        if (rw == 0) {
-                                kdb_id1(ef->eip);
-                        }
-#endif
-
-                        goto handled;
-                }
-        }
-
-#if 0
-unknown:
-#endif
-        kdb_printf("Unknown breakpoint.  Should forward. \n");
-	/* Need a flag for this. The skip should be done XXX
-	 * when a go or single step command is done for this session.
-	 * For now it is here.
- 	 */
-	ia64_increment_ip(ef) ;
-	return rv ;
-
-handled:
-
-	/* We are here after handling a break inst/data bkpt */
-	if (kdb_state.bkpt_handling_state == BKPTSTATE_NOT_HANDLED) {
-		kdb_state.bkpt_handling_state = BKPTSTATE_HANDLED ;
-		if (kdb_state.reason_for_entry == ENTRYREASON_GO) {
-			kdb_setsinglestep(ef) ;
-			kdb_state.kdb_action = ACTION_NOBPINSTALL; 
-			/* We dont want bp install just this once */
-			kdb_state.cmd_given = CMDGIVEN_UNKNOWN ;
-		}
-	} else if (kdb_state.bkpt_handling_state == BKPTSTATE_HANDLED) {
-                kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ;
-                if (kdb_state.reason_for_entry == ENTRYREASON_SSTEP) {
-			if (kdb_state.cmd_given == CMDGIVEN_GO)
-				kdb_state.kdb_action = ACTION_NOPROMPT ;
-			kdb_state.cmd_given = CMDGIVEN_UNKNOWN ;
-		}
-	} else
-		kdb_printf("Unknown value of bkpt state\n") ;
-
-	return rv;
-
-}
-
-void
-kdb_setsinglestep(struct pt_regs *regs)
-{
-	regs->cr_ipsr |= 0x0000010000000000;
-#if 0
-	regs->eflags |= EF_TF;
-#endif
-}
-
-/*
- * Symbol table functions.
- */
-
-/*
- * kdbgetsym
- *
- *	Return the symbol table entry for the given symbol
- *
- * Parameters:
- * 	symname	Character string containing symbol name
- * Outputs:
- * Returns:
- *	NULL	Symbol doesn't exist
- *	ksp	Pointer to symbol table entry
- * Locking:
- *	None.
- * Remarks:
- */
-
-__ksymtab_t *
-kdbgetsym(const char *symname)
-{
-	__ksymtab_t *ksp = __kdbsymtab;
-	int i;
-
-	if (symname == NULL)
-		return NULL;
-
-	for (i=0; i<__kdbsymtabsize; i++, ksp++) {
-		if (ksp->name && (strcmp(ksp->name, symname)==0)) {
-			return ksp;
-		}
-	}
-
-	return NULL;
-}
-
-/*
- * kdbgetsymval
- *
- *	Return the address of the given symbol.
- *
- * Parameters:
- * 	symname	Character string containing symbol name
- * Outputs:
- * Returns:
- *	0	Symbol name is NULL
- *	addr	Address corresponding to symname
- * Locking:
- *	None.
- * Remarks:
- */
-
-unsigned long
-kdbgetsymval(const char *symname)
-{
-	__ksymtab_t *ksp = kdbgetsym(symname);
-
-	return (ksp?ksp->value:0);
-}
-
-/*
- * kdbaddmodsym
- *
- *	Add a symbol to the kernel debugger symbol table.  Called when
- *	a new module is loaded into the kernel.
- *
- * Parameters:
- * 	symname	Character string containing symbol name
- *	value	Value of symbol
- * Outputs:
- * Returns:
- *	0	Successfully added to table.
- *	1	Duplicate symbol
- *	2	Symbol table full
- * Locking:
- *	None.
- * Remarks:
- */
-
-int
-kdbaddmodsym(char *symname, unsigned long value) 
-{
-
-	/*
-	 * Check for duplicate symbols.
-	 */
-	if (kdbgetsym(symname)) {
-		printk("kdb: Attempt to register duplicate symbol '%s' @ 0x%lx\n",
-			symname, value);
-		return 1;
-	}
-
-	if (__kdbsymtabsize < __kdbmaxsymtabsize) {
-		__ksymtab_t *ksp = &__kdbsymtab[__kdbsymtabsize++];
-		
-		ksp->name = symname;
-		ksp->value = value;
-		return 0;
-	}
-
-	/*
-	 * No room left in kernel symbol table.
-	 */
-	{
-		static int __kdbwarn = 0;
-
-		if (__kdbwarn == 0) {
-			__kdbwarn++;
-			printk("kdb: Exceeded symbol table size.  Increase CONFIG_KDB_SYMTAB_SIZE in kernel configuration\n");
-		}
-	}
-
-	return 2;
-}
-
-/*
- * kdbdelmodsym
- *
- *	Add a symbol to the kernel debugger symbol table.  Called when
- *	a new module is loaded into the kernel.
- *
- * Parameters:
- * 	symname	Character string containing symbol name
- *	value	Value of symbol
- * Outputs:
- * Returns:
- *	0	Successfully added to table.
- *	1	Symbol not found
- * Locking:
- *	None.
- * Remarks:
- */
-
-int
-kdbdelmodsym(const char *symname)
-{
-	__ksymtab_t *ksp, *endksp;
-
-	if (symname == NULL)
-		return 1;
-
-	/*
-	 * Search for the symbol.  If found, move 
-	 * all successive symbols down one position
-	 * in the symbol table to avoid leaving holes.
-	 */
-	endksp = &__kdbsymtab[__kdbsymtabsize];
-	for (ksp = __kdbsymtab; ksp < endksp; ksp++) {
-		if (ksp->name && (strcmp(ksp->name, symname) == 0)) {
-			endksp--;
-			for ( ; ksp < endksp; ksp++) {
-				*ksp = *(ksp + 1);
-			}
-			__kdbsymtabsize--;
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-/*
- * kdbnearsym
- *
- *	Return the name of the symbol with the nearest address
- *	less than 'addr'.
- *
- * Parameters:
- * 	addr	Address to check for symbol near
- * Outputs:
- * Returns:
- *	NULL	No symbol with address less than 'addr'
- *	symbol	Returns the actual name of the symbol.
- * Locking:
- *	None.
- * Remarks:
- */
-
-char *
-kdbnearsym(unsigned long addr)
-{
-	__ksymtab_t *ksp = __kdbsymtab;
-	__ksymtab_t *kpp = NULL;
-	int i;
-
-	for(i=0; i<__kdbsymtabsize; i++, ksp++) {
-		if (!ksp->name) 
-			continue;
-
-		if (addr == ksp->value) {
-			kpp = ksp;
-			break;
-		}
-		if (addr > ksp->value) {
-			if ((kpp == NULL) 
-			 || (ksp->value > kpp->value)) {
-				kpp = ksp;
-			}
-		}
-	}
-
-	/*
-	 * If more than 128k away, don't bother.
-	 */
-	if ((kpp == NULL)
-	 || ((addr - kpp->value) > 0x20000)) {
-		return NULL;
-	}
-
-	return kpp->name;
-}
-
-/*
- * kdbgetregcontents
- *
- *	Return the contents of the register specified by the 
- *	input string argument.   Return an error if the string
- *	does not match a machine register.
- *
- *	The following pseudo register names are supported:
- *	   &regs	 - Prints address of exception frame
- *	   kesp		 - Prints kernel stack pointer at time of fault
- * 	   sstk		 - Prints switch stack for ia64
- *	   %<regname>	 - Uses the value of the registers at the 
- *			   last time the user process entered kernel
- *			   mode, instead of the registers at the time
- *			   kdb was entered.
- *
- * Parameters:
- *	regname		Pointer to string naming register
- *	regs		Pointer to structure containing registers.
- * Outputs:
- *	*contents	Pointer to unsigned long to recieve register contents
- * Returns:
- *	0		Success
- *	KDB_BADREG	Invalid register name
- * Locking:
- * 	None.
- * Remarks:
- *
- * 	Note that this function is really machine independent.   The kdb
- *	register list is not, however.
- */
-
-static struct kdbregs {
-	char   *reg_name;
-	size_t	reg_offset;
-} kdbreglist[] = {
-        { " psr",	offsetof(struct pt_regs, cr_ipsr) },
-	{ " ifs",	offsetof(struct pt_regs, cr_ifs) }, 
-        { "  ip",	offsetof(struct pt_regs, cr_iip) },
-
-	{ "unat", 	offsetof(struct pt_regs, ar_unat) },
-	{ " pfs",	offsetof(struct pt_regs, ar_pfs) },
-	{ " rsc", 	offsetof(struct pt_regs, ar_rsc) },
-
-	{ "rnat",	offsetof(struct pt_regs, ar_rnat) },
-	{ "bsps",	offsetof(struct pt_regs, ar_bspstore) },
-	{ "  pr",	offsetof(struct pt_regs, pr) },
-
-	{ "ldrs",	offsetof(struct pt_regs, loadrs) },
-	{ " ccv",	offsetof(struct pt_regs, ar_ccv) },
-	{ "fpsr",	offsetof(struct pt_regs, ar_fpsr) },
-
-	{ "  b0",	offsetof(struct pt_regs, b0) },
-	{ "  b6",	offsetof(struct pt_regs, b6) },
-	{ "  b7",	offsetof(struct pt_regs, b7) },
-
-	{ "  r1",offsetof(struct pt_regs, r1) },
-        { "  r2",offsetof(struct pt_regs, r2) },
-        { "  r3",offsetof(struct pt_regs, r3) },
-
-        { "  r8",offsetof(struct pt_regs, r8) },
-        { "  r9",offsetof(struct pt_regs, r9) },
-        { " r10",offsetof(struct pt_regs, r10) },
-
-	{ " r11",offsetof(struct pt_regs, r11) },
-        { " r12",offsetof(struct pt_regs, r12) },
-        { " r13",offsetof(struct pt_regs, r13) },
-
-        { " r14",offsetof(struct pt_regs, r14) },
-        { " r15",offsetof(struct pt_regs, r15) },
-        { " r16",offsetof(struct pt_regs, r16) },
-
-        { " r17",offsetof(struct pt_regs, r17) },
-        { " r18",offsetof(struct pt_regs, r18) },
-        { " r19",offsetof(struct pt_regs, r19) },
-
-        { " r20",offsetof(struct pt_regs, r20) },
-        { " r21",offsetof(struct pt_regs, r21) },
-        { " r22",offsetof(struct pt_regs, r22) },
-
-        { " r23",offsetof(struct pt_regs, r23) },
-        { " r24",offsetof(struct pt_regs, r24) },
-        { " r25",offsetof(struct pt_regs, r25) },
-
-        { " r26",offsetof(struct pt_regs, r26) },
-        { " r27",offsetof(struct pt_regs, r27) },
-        { " r28",offsetof(struct pt_regs, r28) },
-
-        { " r29",offsetof(struct pt_regs, r29) },
-        { " r30",offsetof(struct pt_regs, r30) },
-        { " r31",offsetof(struct pt_regs, r31) },
-
-};
-
-static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs);
-
-int
-kdbgetregcontents(const char *regname, 
-		  struct pt_regs *regs,
-		  unsigned long *contents)
-{
-	int i;
-
-	if (strcmp(regname, "&regs") == 0) {
-		*contents = (unsigned long)regs;
-		return 0;
-	}
-
-	if (strcmp(regname, "sstk") == 0) {
-		*contents = (unsigned long)getprsregs(regs) ;
-		return 0;
-	}
-
-	if (strcmp(regname, "isr") == 0) {
-		fault_regs_t fr ;
-		get_fault_regs(&fr) ;
-		*contents = fr.isr ;
-		return 0 ;
-	} 
-
-#if 0
-	/* XXX need to verify this */
-        if (strcmp(regname, "kesp") == 0) {
-                *contents = (unsigned long)regs + sizeof(struct pt_regs);
-                return 0;
-        }
-
-	if (regname[0] == '%') {
-		/* User registers:  %%e[a-c]x, etc */
-		regname++;
-		regs = (struct pt_regs *)
-			(current->thread.ksp - sizeof(struct pt_regs));
-	}
-#endif
-
-	for (i=0; i<nkdbreglist; i++) {
-		if (strstr(kdbreglist[i].reg_name, regname))
-			break;
-	}
-
-	if (i == nkdbreglist) {
-		/* Lets check the rse maybe */
-		if (regname[0] == 'r')
-			if (show_cur_stack_frame(regs, simple_strtoul(regname+1, 0, 0) - 31, 
-					contents))
-				return 0 ;
-		return KDB_BADREG;
-	}
-
-	*contents = *(unsigned long *)((unsigned long)regs +
-			kdbreglist[i].reg_offset);
-
-	return 0;
-}
-
-/*
- * kdbsetregcontents
- *
- *	Set the contents of the register specified by the 
- *	input string argument.   Return an error if the string
- *	does not match a machine register.
- *
- *	Supports modification of user-mode registers via
- *	%<register-name>
- *
- * Parameters:
- *	regname		Pointer to string naming register
- *	regs		Pointer to structure containing registers.
- *	contents	Unsigned long containing new register contents
- * Outputs:
- * Returns:
- *	0		Success
- *	KDB_BADREG	Invalid register name
- * Locking:
- * 	None.
- * Remarks:
- */
-
-int
-kdbsetregcontents(const char *regname, 
-		  struct pt_regs *regs,
-		  unsigned long contents)
-{
-	int i;
-
-	if (regname[0] == '%') {
-		regname++;
-		regs = (struct pt_regs *)
-			(current->thread.ksp - sizeof(struct pt_regs));
-	}
-
-	for (i=0; i<nkdbreglist; i++) {
-		if (strnicmp(kdbreglist[i].reg_name, 
-			     regname, 
-			     strlen(regname)) == 0)
-			break;
-	}
-
-	if ((i == nkdbreglist) 
-	 || (strlen(kdbreglist[i].reg_name) != strlen(regname))) {
-		return KDB_BADREG;
-	}
-
-	*(unsigned long *)((unsigned long)regs + kdbreglist[i].reg_offset) = 
-		contents;
-
-	return 0;
-}
-
-/*
- * kdbdumpregs
- *
- *	Dump the specified register set to the display.
- *
- * Parameters:
- *	regs		Pointer to structure containing registers.
- *	type		Character string identifying register set to dump
- *	extra		string further identifying register (optional)
- * Outputs:
- * Returns:
- *	0		Success
- * Locking:
- * 	None.
- * Remarks:
- *	This function will dump the general register set if the type
- *	argument is NULL (struct pt_regs).   The alternate register 
- *	set types supported by this function:
- *
- *	d 		Debug registers
- *	c		Control registers
- *	u		User registers at most recent entry to kernel
- * Following not yet implemented:
- *	m		Model Specific Registers (extra defines register #)
- *	r		Memory Type Range Registers (extra defines register)
- *
- *	For now, all registers are covered as follows:
- *
- * 	rd 		- dumps all regs
- *	rd	%isr	- current interrupt status reg, read freshly
- *	rd	s	- valid stacked regs
- * 	rd 	%sstk	- gets switch stack addr. dump memory and search
- *	rd	d	- debug regs, may not be too useful
- *
- *	ARs		TB Done
- *	Interrupt regs 	TB Done ??
- *	OTHERS		TB Decided ??
- *
- *	Intel wish list
- *	These will be implemented later - Srinivasa
- *
- *      type        action
- *      ----        ------
- *      g           dump all General static registers
- *      s           dump all general Stacked registers
- *      f           dump all Floating Point registers
- *      p           dump all Predicate registers
- *      b           dump all Branch registers
- *      a           dump all Application registers
- *      c           dump all Control registers
- *
- */
-
-int
-kdbdumpregs(struct pt_regs *regs,
-	    const char *type,
-	    const char *extra)
-
-{
-	int i;
-	int count = 0;
-
-	if (type 
-	 && (type[0] == 'u')) {
-		type = NULL;
-		regs = (struct pt_regs *)
-			(current->thread.ksp - sizeof(struct pt_regs));
-	}
-
-	if (type == NULL) {
-		for (i=0; i<nkdbreglist; i++) {
-			kdb_printf("%s: 0x%16.16lx  ", 
-				   kdbreglist[i].reg_name, 
-				   *(unsigned long *)((unsigned long)regs + 
-						  kdbreglist[i].reg_offset));
-
-			if ((++count % 3) == 0)
-				kdb_printf("\n");
-		}
-
-		kdb_printf("&regs = 0x%16.16lx\n", regs);
-
-		return 0;
-	}
-
-	switch (type[0]) {
-	case 'd':
-	{
-		for(i=0; i<8; i+=2) {
-			kdb_printf("idr%d: 0x%16.16lx  idr%d: 0x%16.16lx\n", i, 
-					kdb_getdr(i), i+1, kdb_getdr(i+1));
-					
-		}
-		return 0;
-	}
-#if 0
-	case 'c':
-	{
-		unsigned long cr[5];
-
-		for (i=0; i<5; i++) {
-			cr[i] = kdb_getcr(i);
-		}
-		kdb_printf("cr0 = 0x%8.8x  cr1 = 0x%8.8x  cr2 = 0x%8.8x  cr3 = 0x%8.8x\ncr4 = 0x%8.8x\n",
-			   cr[0], cr[1], cr[2], cr[3], cr[4]);
-		return 0;
-	}
-#endif
-	case 'm':
-		break;
-	case 'r':
-		break;
-
-	case 's':
-	{
-		show_cur_stack_frame(regs, 0, NULL) ;
-
-		return 0 ;
-	}
-
-	case '%':
-	{
-		unsigned long contents ;
-
-		if (!kdbgetregcontents(type+1, regs, &contents))
-                	kdb_printf("%s = 0x%16.16lx\n", type+1, contents) ;
-		else
-                        kdb_printf("diag: Invalid register %s\n", type+1) ;
-
-		return 0 ;
-	}
-
-	default:
-		return KDB_BADREG;
-	}
-
-	/* NOTREACHED */
-	return 0;
-}
-
-k_machreg_t
-kdb_getpc(struct pt_regs *regs)
-{
-	return regs->cr_iip + ia64_psr(regs)->ri;
-}
-
-int
-kdb_setpc(struct pt_regs *regs, k_machreg_t newpc)
-{
-	regs->cr_iip = newpc & ~0xf;
-	ia64_psr(regs)->ri = newpc & 0x3;
-	return 0;
-}
-
-void
-kdb_disableint(kdbintstate_t *state)
-{
-	int *fp = (int *)state;
-	int   flags;
-
-        __save_flags(flags);
-        __cli();
-
-	*fp = flags;
-}
-
-void
-kdb_restoreint(kdbintstate_t *state)
-{
-	int flags = *(int *)state;
-	__restore_flags(flags);
-}
-
-int
-kdb_putword(unsigned long addr, unsigned long contents)
-{
-	*(unsigned long *)addr = contents;
-	return 0;
-}	
-
-int
-kdb_getcurrentframe(struct pt_regs *regs)
-{
-#if 0
-	regs->xcs = 0;
-#if defined(CONFIG_KDB_FRAMEPTR)
-	asm volatile("movl %%ebp,%0":"=m" (*(int *)&regs->ebp));
-#endif
-	asm volatile("movl %%esp,%0":"=m" (*(int *)&regs->esp));
-#endif
-	return 0;
-}
-
-unsigned long
-show_cur_stack_frame(struct pt_regs *regs, int regno, unsigned long *contents)
-{
-        long sof = regs->cr_ifs & ((1<<7)-1) ;	/* size of frame */
-        unsigned long   i ;
-	int j;
-	struct switch_stack *prs_regs = getprsregs(regs) ;
-        unsigned long *sofptr = (prs_regs? ia64_rse_skip_regs(
-			(unsigned long *)prs_regs->ar_bspstore, -sof) : NULL) ;
-
-	if (!sofptr) {
-		printk("Unable to display Current Stack Frame\n") ;
-		return 0 ;
-	}
-
-	if (regno < 0) 
-		return 0 ;
-
-	for (i=sof, j=0;i;i--,j++) {
-		/* remember to skip the nat collection dword */
-		if ((((unsigned long)sofptr>>3) & (((1<<6)-1))) 
-				== ((1<<6)-1))
-			sofptr++ ;
-
-		/* return the value in the reg if regno is non zero */
-
-		if (regno) {
-			if ((j+1) == regno) {
-				if (contents)
-					*contents = *sofptr ;
-				return -1;
-			}
-			sofptr++ ;
-		} else {
-			printk(" r%d: %016lx ", 32+j, *sofptr++) ;
-			if (!((j+1)%3)) printk("\n") ;
-		}
-	}
-
-	if (regno) {
-		if (!i) /* bogus rse number */
-			return 0 ;
-	} else
-		printk("\n") ;
-
-	return 0 ;
-}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/pc_keyb.h linux/arch/ia64/kdb/pc_keyb.h
--- v2.3.99-pre5/linux/arch/ia64/kdb/pc_keyb.h	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kdb/pc_keyb.h	Wed Dec 31 16:00:00 1969
@@ -1,127 +0,0 @@
-/*
- *	linux/drivers/char/pc_keyb.h
- *
- *	PC Keyboard And Keyboard Controller
- *
- *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- */
-
-/*
- *	Configuration Switches
- */
-
-#undef KBD_REPORT_ERR			/* Report keyboard errors */
-#define KBD_REPORT_UNKN			/* Report unknown scan codes */
-#define KBD_REPORT_TIMEOUTS		/* Report keyboard timeouts */
-#undef KBD_IS_FOCUS_9000		/* We have the brain-damaged FOCUS-9000 keyboard */
-#undef INITIALIZE_MOUSE			/* Define if your PS/2 mouse needs initialization. */
-
-
-
-#define KBD_INIT_TIMEOUT 1000		/* Timeout in ms for initializing the keyboard */
-#define KBC_TIMEOUT 250			/* Timeout in ms for sending to keyboard controller */
-#define KBD_TIMEOUT 1000		/* Timeout in ms for keyboard command acknowledge */
-
-/*
- *	Internal variables of the driver
- */
-
-extern unsigned char pckbd_read_mask;
-extern unsigned char aux_device_present;
-
-/*
- *	Keyboard Controller Registers
- */
-
-#define KBD_STATUS_REG		0x64	/* Status register (R) */
-#define KBD_CNTL_REG		0x64	/* Controller command register (W) */
-#define KBD_DATA_REG		0x60	/* Keyboard data register (R/W) */
-
-/*
- *	Keyboard Controller Commands
- */
-
-#define KBD_CCMD_READ_MODE	0x20	/* Read mode bits */
-#define KBD_CCMD_WRITE_MODE	0x60	/* Write mode bits */
-#define KBD_CCMD_GET_VERSION	0xA1	/* Get controller version */
-#define KBD_CCMD_MOUSE_DISABLE	0xA7	/* Disable mouse interface */
-#define KBD_CCMD_MOUSE_ENABLE	0xA8	/* Enable mouse interface */
-#define KBD_CCMD_TEST_MOUSE	0xA9	/* Mouse interface test */
-#define KBD_CCMD_SELF_TEST	0xAA	/* Controller self test */
-#define KBD_CCMD_KBD_TEST	0xAB	/* Keyboard interface test */
-#define KBD_CCMD_KBD_DISABLE	0xAD	/* Keyboard interface disable */
-#define KBD_CCMD_KBD_ENABLE	0xAE	/* Keyboard interface enable */
-#define KBD_CCMD_WRITE_AUX_OBUF	0xD3    /* Write to output buffer as if
-					   initiated by the auxiliary device */
-#define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
-
-/*
- *	Keyboard Commands
- */
-
-#define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
-#define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
-#define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
-#define KBD_CMD_DISABLE		0xF5	/* Disable scanning */
-#define KBD_CMD_RESET		0xFF	/* Reset */
-
-/*
- *	Keyboard Replies
- */
-
-#define KBD_REPLY_POR		0xAA	/* Power on reset */
-#define KBD_REPLY_ACK		0xFA	/* Command ACK */
-#define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
-
-/*
- *	Status Register Bits
- */
-
-#define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
-#define KBD_STAT_IBF 		0x02	/* Keyboard input buffer full */
-#define KBD_STAT_SELFTEST	0x04	/* Self test successful */
-#define KBD_STAT_CMD		0x08	/* Last write was a command write (0=data) */
-#define KBD_STAT_UNLOCKED	0x10	/* Zero if keyboard locked */
-#define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
-#define KBD_STAT_GTO 		0x40	/* General receive/xmit timeout */
-#define KBD_STAT_PERR 		0x80	/* Parity error */
-
-#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
-
-/*
- *	Controller Mode Register Bits
- */
-
-#define KBD_MODE_KBD_INT	0x01	/* Keyboard data generate IRQ1 */
-#define KBD_MODE_MOUSE_INT	0x02	/* Mouse data generate IRQ12 */
-#define KBD_MODE_SYS 		0x04	/* The system flag (?) */
-#define KBD_MODE_NO_KEYLOCK	0x08	/* The keylock doesn't affect the keyboard if set */
-#define KBD_MODE_DISABLE_KBD	0x10	/* Disable keyboard interface */
-#define KBD_MODE_DISABLE_MOUSE	0x20	/* Disable mouse interface */
-#define KBD_MODE_KCC 		0x40	/* Scan code conversion to PC format */
-#define KBD_MODE_RFU		0x80
-
-/*
- *	Mouse Commands
- */
-
-#define AUX_SET_RES		0xE8	/* Set resolution */
-#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
-#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
-#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
-#define AUX_SET_STREAM		0xEA	/* Set stream mode */
-#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
-#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
-#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
-#define AUX_RESET		0xFF	/* Reset aux device */
-
-#define AUX_BUF_SIZE		2048
-
-struct aux_queue {
-	unsigned long head;
-	unsigned long tail;
-	struct wait_queue *proc_list;
-	struct fasync_struct *fasync;
-	unsigned char buf[AUX_BUF_SIZE];
-};
-
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile
--- v2.3.99-pre5/linux/arch/ia64/kernel/Makefile	Tue Apr 11 15:09:12 2000
+++ linux/arch/ia64/kernel/Makefile	Fri Apr 21 15:21:24 2000
@@ -15,13 +15,13 @@
 all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
-O_OBJS	 := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_internal.o ivt.o \
-	    pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o sal_stub.o semaphore.o setup.o signal.o \
-	    sys_ia64.o traps.o time.o unaligned.o unwind.o
+O_OBJS	 := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \
+	    pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o sal_stub.o semaphore.o setup.o \
+	    signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o
 #O_OBJS   := fpreg.o
 #OX_OBJS  := ia64_ksyms.o
 
-ifeq ($(CONFIG_IA64_GENERIC),y)
+ifdef CONFIG_IA64_GENERIC
 O_OBJS	+= machvec.o
 endif
 
@@ -30,10 +30,10 @@
 endif
 
 ifdef CONFIG_SMP
-O_OBJS	+= smp.o irq_lock.o
+O_OBJS	+= smp.o
 endif
 
-ifeq ($(CONFIG_MCA),y)
+ifdef CONFIG_IA64_MCA
 O_OBJS	+= mca.o mca_asm.o
 endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/acpi.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/acpi.c	Fri Apr 21 15:21:24 2000
@@ -11,12 +11,12 @@
 #include <linux/config.h>
 
 #include <linux/init.h>
-#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/irq.h>
 
 #include <asm/acpi-ext.h>
 #include <asm/page.h>
@@ -27,13 +27,12 @@
 #undef ACPI_DEBUG		/* Guess what this does? */
 
 #ifdef CONFIG_SMP
-extern unsigned long ipi_base_addr;
+extern struct smp_boot_data smp;
 #endif
 
 /* These are ugly but will be reclaimed by the kernel */
-int __initdata acpi_cpus = 0;	
-int __initdata acpi_apic_map[32];
-int __initdata cpu_cnt = 0;
+int __initdata available_cpus = 0;	
+int __initdata total_cpus = 0;
 
 void (*pm_idle) (void);
 
@@ -50,7 +49,7 @@
 	if ((lsapic->flags & LSAPIC_PRESENT) == 0) 
 		return;
 
-	printk("      CPU %d (%.04x:%.04x): ", cpu_cnt, lsapic->eid, lsapic->id);
+	printk("      CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id);
 
 	if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
 		printk("Disabled.\n");
@@ -62,11 +61,17 @@
 	
 	if (add) {
 		printk("Available.\n");
-		acpi_cpus++;
-		acpi_apic_map[cpu_cnt] = (lsapic->id << 8) | lsapic->eid;
+		available_cpus++;
+#ifdef CONFIG_SMP
+# if LARGE_CPU_ID_OK
+		smp.cpu_map[total_cpus] = (lsapic->id << 8) | lsapic->eid;
+# else
+		smp.cpu_map[total_cpus] = lsapic->id;
+# endif
+#endif
 	}
 	
-	cpu_cnt++;
+	total_cpus++;
 }
 
 /*
@@ -174,7 +179,7 @@
 		break;
 	}
 
-#ifdef ACPI_DEBUG
+#if 1/*def ACPI_DEBUG*/
 	printk("Legacy ISA IRQ %x -> IA64 Vector %x IOSAPIC Pin %x Active %s %s Trigger\n", 
 	       legacy->isa_irq, vector, iosapic_pin(vector), 
 	       ((iosapic_polarity(vector) == IO_SAPIC_POL_LOW) ? "Low" : "High"),
@@ -204,11 +209,11 @@
 {
 	char *p, *end;
 
-	memset(&acpi_apic_map, -1, sizeof(acpi_apic_map));
+	/* Base address of IPI Message Block */
+	ipi_base_addr = (unsigned long) ioremap(msapic->interrupt_block, 0);
 
 #ifdef CONFIG_SMP
-	/* Base address of IPI Message Block */
-	ipi_base_addr = ioremap(msapic->interrupt_block, 0);
+	memset(&smp, -1, sizeof(smp));
 #endif
 	
 	p = (char *) (msapic + 1);
@@ -238,11 +243,22 @@
 		}
 
 		/* Move to next table entry. */
-		p += *(p + 1);
+#define BAD_ACPI_TABLE
+#ifdef BAD_ACPI_TABLE
+		/*
+		 * Some prototype Lion's have a bad ACPI table
+		 * requiring this fix.  Without this fix, those
+		 * machines crash during bootup.
+		 */
+		if (p[1] == 0)
+			p = end;
+		else
+#endif
+			p += p[1];
 	}
 
 	/* Make bootup pretty */
-	printk("      %d CPUs available, %d CPUs total\n", acpi_cpus, cpu_cnt);
+	printk("      %d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
 }
 
 int __init 
@@ -281,12 +297,15 @@
 			continue;
 
 		acpi_parse_msapic((acpi_sapic_t *) hdrp);
-	} /* while() */
+	}
 
-	if (acpi_cpus == 0) {
+#ifdef CONFIG_SMP
+	if (available_cpus == 0) {
 		printk("ACPI: Found 0 CPUS; assuming 1\n");
-		acpi_cpus = 1; /* We've got at least one of these, no? */
+		available_cpus = 1; /* We've got at least one of these, no? */
 	}
+	smp.cpu_count = available_cpus;
+#endif
 	return 1;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/efi.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/efi.c	Fri Apr 21 15:21:24 2000
@@ -24,7 +24,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 
-#define EFI_DEBUG
+#define EFI_DEBUG	0
 
 extern efi_status_t efi_call_phys (void *, ...);
 
@@ -210,9 +210,8 @@
 void __init 
 efi_init (void)
 {
-	void *efi_map_start, *efi_map_end, *p;
+	void *efi_map_start, *efi_map_end;
 	efi_config_table_t *config_tables;
-	efi_memory_desc_t *md;
 	efi_char16_t *c16;
 	u64 efi_desc_size;
 	char vendor[100] = "unknown";
@@ -278,13 +277,18 @@
 	efi_map_end   = efi_map_start + ia64_boot_param.efi_memmap_size;
 	efi_desc_size = ia64_boot_param.efi_memdesc_size;
 
-#ifdef EFI_DEBUG
+#if EFI_DEBUG
 	/* print EFI memory map: */
-	for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) {
-		md = p;
-		printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
-		       i, md->type, md->attribute,
-		       md->phys_addr, md->phys_addr + (md->num_pages<<12) - 1, md->num_pages >> 8);
+	{
+		efi_memory_desc_t *md = p;
+		void *p;
+
+		for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) {
+			md = p;
+			printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
+			       i, md->type, md->attribute, md->phys_addr,
+			       md->phys_addr + (md->num_pages<<12) - 1, md->num_pages >> 8);
+		}
 	}
 #endif
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S
--- v2.3.99-pre5/linux/arch/ia64/kernel/entry.S	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/entry.S	Fri Apr 21 15:21:24 2000
@@ -25,6 +25,7 @@
 
 #include <linux/config.h>
 
+#include <asm/cache.h>
 #include <asm/errno.h>
 #include <asm/offsets.h>
 #include <asm/processor.h>
@@ -228,11 +229,11 @@
 	stf.spill [r2]=f30,32
 	stf.spill [r3]=f31,24
 	;;
-	st8.spill [r2]=r4,16
-	st8.spill [r3]=r5,16
+.mem.offset 0,0;	st8.spill [r2]=r4,16
+.mem.offset 8,0;	st8.spill [r3]=r5,16
 	;;
-	st8.spill [r2]=r6,16
-	st8.spill [r3]=r7,16
+.mem.offset 0,0;	st8.spill [r2]=r6,16
+.mem.offset 8,0;	st8.spill [r3]=r7,16
 	;;
 	st8 [r2]=r21,16		// save b0
 	st8 [r3]=r22,16		// save b1
@@ -437,8 +438,8 @@
 (p6)	br.cond.sptk.few strace_error		// syscall failed ->
 	;;					// avoid RAW on r10
 strace_save_retval:
-	st8.spill [r2]=r8			// store return value in slot for r8
-	st8.spill [r3]=r10			// clear error indication in slot for r10
+.mem.offset 0,0;	st8.spill [r2]=r8	// store return value in slot for r8
+.mem.offset 8,0;	st8.spill [r3]=r10	// clear error indication in slot for r10
 ia64_strace_leave_kernel:
 	br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value
 .ret6:	br.cond.sptk.many ia64_leave_kernel
@@ -491,7 +492,9 @@
 	adds r2=IA64_PT_REGS_R8_OFFSET+16,sp	// r2 = &pt_regs.r8
 	adds r3=IA64_PT_REGS_R8_OFFSET+32,sp	// r3 = &pt_regs.r10
 	;;
+	.mem.offset 0,0
 (p6)	st8.spill [r2]=r8	// store return value in slot for r8 and set unat bit
+	.mem.offset 8,0
 (p6)	st8.spill [r3]=r0	// clear error indication in slot for r10 and set unat bit
 (p7)	br.cond.spnt.few handle_syscall_error	// handle potential syscall failure
 
@@ -504,7 +507,9 @@
 	;;
 	ld4	r2=[r2]
 	;;
-	shladd	r3=r2,3,r3
+	shl	r2=r2,SMP_LOG_CACHE_BYTES	// can't use shladd here...
+	;;
+	add	r3=r2,r3
 #else
 	movl r3=softirq_state
 #endif
@@ -550,6 +555,16 @@
 2:
 	// check & deliver pending signals:
 (p2)	br.call.spnt.few rp=handle_signal_delivery
+#if defined(CONFIG_SMP) || defined(CONFIG_IA64_SOFTSDV_HACKS)
+	// Check for lost ticks
+	mov r2 = ar.itc
+	mov r3 = cr.itm
+	;;
+	sub r2 = r2, r3
+	;;
+	cmp.ge p6,p7 = r2, r0
+(p6)	br.call.spnt.few rp=invoke_ia64_reset_itm
+#endif 
 restore_all:
 
 	// start restoring the state saved on the kernel stack (struct pt_regs):
@@ -735,8 +750,8 @@
 (p6)	mov r9=r8
 (p6)	mov r10=0
 	;;
-	st8.spill [r2]=r9	// store errno in pt_regs.r8 and set unat bit
-	st8.spill [r3]=r10	// store error indication in pt_regs.r10 and set unat bit
+.mem.offset 0,0; st8.spill [r2]=r9	// store errno in pt_regs.r8 and set unat bit
+.mem.offset 8,0; st8.spill [r3]=r10	// store error indication in pt_regs.r10 and set unat bit
 	br.cond.sptk.many ia64_leave_kernel
 	.endp handle_syscall_error
 
@@ -757,6 +772,19 @@
 	mov rp=loc1
 	br.ret.sptk.many rp
 	.endp invoke_schedule_tail
+
+	.proc invoke_ia64_reset_itm
+invoke_ia64_reset_itm:
+	alloc loc0=ar.pfs,8,2,0,0
+	mov loc1=rp
+	;;
+	br.call.sptk.many rp=ia64_reset_itm
+	;;
+	mov ar.pfs=loc0
+	mov rp=loc1
+	br.ret.sptk.many rp
+	.endp invoke_ia64_reset_itm
+
 #endif /* CONFIG_SMP */
 
 	/*
@@ -855,26 +883,22 @@
 	.global sys_rt_sigsuspend
 sys_rt_sigsuspend:
 	alloc loc0=ar.pfs,2,2,3,0
-	mov r9=ar.unat
 
 	// If the process is being ptraced, the signal may not actually be delivered to
 	// the process.  Instead, SIGCHLD will be sent to the parent.  We need to
 	// setup a switch_stack so ptrace can inspect the processes state if necessary.
-	adds r2=IA64_TASK_FLAGS_OFFSET,r13
-	;;
-	ld8 r2=[r2]
+	// Also, the process might not ptraced until stopped in sigsuspend, so this
+	// isn't something that we can do conditionally based upon the value of
+	// PF_PTRACED_BIT.
 	mov out0=in0				// mask
 	mov out1=in1				// sigsetsize
 	;;
 	adds out2=16,sp				// out1=&pt_regs
-	tbit.nz p16,p17=r2,PF_PTRACED_BIT
-(p16)	br.cond.spnt.many sigsuspend_setup_switch_stack
+	movl r28=back_from_sigsuspend_setup_switch_stack
+	mov r16=loc0
+	br.cond.sptk.many save_switch_stack
 	;;
 back_from_sigsuspend_setup_switch_stack:
-	adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
-(p17)	adds sp=-IA64_SWITCH_STACK_SIZE,sp	// make space for (dummy) switch_stack
-	;;
-(p17)	st8 [r3]=r9				// save ar.unat in sw->caller_unat
 	mov loc1=rp				// save return address
 	br.call.sptk.many rp=ia64_rt_sigsuspend
 .ret12:
@@ -883,32 +907,22 @@
 	ld8 r9=[r3]				// load new unat from sw->caller_unat
 	mov rp=loc1
 	;;
-(p17)	adds sp=IA64_SWITCH_STACK_SIZE,sp	// drop (dummy) switch_stack
-(p17)	mov ar.unat=r9
-(p17)	mov ar.pfs=loc0
-(p17)	br.ret.sptk.many rp
 
 	// restore the switch stack (ptrace may have modified it):
 	movl r28=1f
 	br.cond.sptk.many load_switch_stack
 1:	br.ret.sptk.many rp
 	// NOT REACHED
-
-sigsuspend_setup_switch_stack:
-	movl r28=back_from_sigsuspend_setup_switch_stack
-	mov r16=loc0
-	br.cond.sptk.many save_switch_stack
-	// NOT REACHED
-
 	.endp sys_rt_sigsuspend
 
 	.align 16
 	.proc sys_rt_sigreturn
 sys_rt_sigreturn:
-	alloc loc0=ar.pfs,8,1,1,0 // preserve all eight input regs in case of syscall restart!
+	.regstk 0,0,3,0	// inherited from gate.s:invoke_sighandler()
 	adds out0=16,sp				// out0 = &pt_regs
-	;;
 	adds sp=-IA64_SWITCH_STACK_SIZE,sp	// make space for unat and padding
+	;;
+	cmp.eq pNonSys,p0=r0,r0			// sigreturn isn't a normal syscall...
 	br.call.sptk.few rp=ia64_rt_sigreturn
 .ret13:
 	adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
@@ -918,8 +932,7 @@
 	;;
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// drop (dummy) switch-stack frame
 	mov ar.unat=r9
-	mov ar.pfs=loc0
-	br.ret.sptk.many rp
+	br rp
 	.endp sys_rt_sigreturn
 
 	.align 16
@@ -940,76 +953,6 @@
 2:	br.cond.sptk.many rp			  // goes to ia64_leave_kernel
 	.endp ia64_prepare_handle_unaligned
 
-#ifdef CONFIG_KDB
-	//
-	// This gets called from ivt.S with:
-	//	SAVE MIN with cover done
-	//	SAVE REST done
-	//	no parameters
-	//	r15 has return value = ia64_leave_kernel
-	//
-	.align 16
-	.global ia64_invoke_kdb
-	.proc ia64_invoke_kdb
-ia64_invoke_kdb:
-	alloc r16=ar.pfs,0,0,4,0
-	movl r28=1f				// save_switch_stack protocol
-	;;			// avoid WAW on CFM
-	br.cond.sptk.many save_switch_stack	// to flushrs
-1:	mov out0=4				// kdb entry reason
-	mov out1=0				// err number
-	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// pt_regs
-	add out3=16,sp				// switch_stack
-	br.call.sptk.few rp=kdb
-.ret15:
-	movl r28=1f				// load_switch_stack proto
-	br.cond.sptk.many load_switch_stack
-1:	br.ret.sptk.many rp
-	.endp ia64_invoke_kdb
-
-	//
-	// When KDB is compiled in, we intercept each fault and give
-	// kdb a chance to run before calling the normal fault handler.
-	//
-        .align 16
-        .global ia64_invoke_kdb_fault_handler
-        .proc ia64_invoke_kdb_fault_handler
-ia64_invoke_kdb_fault_handler:
-        alloc r16=ar.pfs,5,1,5,0
-        movl r28=1f
-	mov loc0=rp			// save this
-	br.cond.sptk.many save_switch_stack // to flushrs
-	;;			// avoid WAW on CFM
-1:	mov out0=in0			// vector number
-	mov out1=in1			// cr.isr
-	mov out2=in2			// cr.ifa
-	mov out3=in3			// cr.iim
-	mov out4=in4			// cr.itir
-	br.call.sptk.few rp=ia64_kdb_fault_handler
-.ret16:
-
-	movl r28=1f
-	br.cond.sptk.many load_switch_stack
-1:	cmp.ne p6,p0=r8,r0		// did ia64_kdb_fault_handler return 0?
-	mov rp=loc0
-(p6)	br.ret.spnt.many rp		// no, we're done
-	;;		// avoid WAW on rp
-	mov out0=in0			// vector number
-	mov out1=in1			// cr.isr
-	mov out2=in2			// cr.ifa
-	mov out3=in3			// cr.iim
-	mov out4=in4			// cr.itir
-	mov in0=ar.pfs			// preserve ar.pfs returned by load_switch_stack
-	br.call.sptk.few rp=ia64_fault	// yup -> we need to invoke normal fault handler now
-.ret17:
-	mov ar.pfs=in0
-	mov rp=loc0
-	br.ret.sptk.many rp
-
-	.endp ia64_invoke_kdb_fault_handler
-
-#endif /* CONFIG_KDB */
-
 	.rodata
 	.align 8
 	.globl sys_call_table
@@ -1198,8 +1141,8 @@
 	data8 sys_sendmsg			// 1205
 	data8 sys_recvmsg
 	data8 sys_pivot_root
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
+	data8 sys_mincore
+	data8 sys_madvise
 	data8 ia64_ni_syscall			// 1210
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S
--- v2.3.99-pre5/linux/arch/ia64/kernel/gate.S	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/gate.S	Fri Apr 21 15:21:24 2000
@@ -80,8 +80,6 @@
 ia64_sigtramp:
 	ld8 r10=[r3],8				// get signal handler entry point
 	br.call.sptk.many rp=invoke_sighandler
-.ret0:	mov r15=__NR_rt_sigreturn
-	break __BREAK_SYSCALL
 	.endp ia64_sigtramp
 
 	.proc invoke_sighandler
@@ -90,10 +88,9 @@
 	mov b6=r10
 	cover				// push args in interrupted frame onto backing store
 	;;
-	alloc r8=ar.pfs,0,1,3,0		// get CFM0, EC0, and CPL0 into r8
-	mov r17=ar.bsp			// fetch ar.bsp
-	mov loc0=rp			// save return pointer
+	alloc r8=ar.pfs,0,0,3,0		// get CFM0, EC0, and CPL0 into r8
 	;;
+	mov r17=ar.bsp			// fetch ar.bsp
 	cmp.ne p8,p0=r15,r0		// do we need to switch the rbs?
 	mov out0=r2			// signal number
 (p8)	br.cond.spnt.few setup_rbs	// yup -> (clobbers r14 and r16)
@@ -101,10 +98,11 @@
 	adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
 	;;
 	st8 [base0]=r17,(CFM_OFF-BSP_OFF)	// save sc_ar_bsp
+	dep r8=0,r8,38,26		// clear EC0, CPL0 and reserved bits
 	adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
 	;;
 
-	st8 [base0]=r8				// save CFM0, EC0, and CPL0
+	st8 [base0]=r8				// save CFM0
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
 	;;
 	stf.spill [base0]=f6,32
@@ -124,7 +122,8 @@
 	stf.spill [base0]=f14,32
 	stf.spill [base1]=f15,32
 	br.call.sptk.few rp=b6			// call the signal handler
-.ret2:	adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
+.ret2:
+	adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
 	;;
 	ld8 r15=[base0],(CFM_OFF-BSP_OFF)	// fetch sc_ar_bsp and advance to CFM_OFF
 	mov r14=ar.bsp
@@ -134,23 +133,11 @@
 (p8)	br.cond.spnt.few restore_rbs		// yup -> (clobbers r14 and r16)
 	;;
 back_from_restore_rbs:
-	{
-	  and r9=0x7f,r8			// r9  <- CFM0.sof
-	  extr.u r10=r8,7,7			// r10 <- CFM0.sol
-	  mov r11=ip
-	}
-	;;
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
-	adds r11=(cont-back_from_restore_rbs),r11
-	sub r9=r9,r10				// r9 <- CFM0.sof - CFM0.sol == CFM0.nout
-	;;
 	adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
-	dep r9=r9,r9,7,7			// r9.sol = r9.sof
-	mov b6=r11
 	;;
 	ldf.fill f6=[base0],32
 	ldf.fill f7=[base1],32
-	mov rp=loc0			// copy return pointer out of stacked register
 	;;
 	ldf.fill f8=[base0],32
 	ldf.fill f9=[base1],32
@@ -160,26 +147,23 @@
 	;;
 	ldf.fill f12=[base0],32
 	ldf.fill f13=[base1],32
-	mov ar.pfs=r9
 	;;
 	ldf.fill f14=[base0],32
 	ldf.fill f15=[base1],32
-	br.ret.sptk.few b6
-cont:	mov ar.pfs=r8				// ar.pfs = CFM0
-	br.ret.sptk.few rp			// re-establish CFM0
+	mov r15=__NR_rt_sigreturn
+	break __BREAK_SYSCALL
 	.endp invoke_sighandler
 
 	.proc setup_rbs
 setup_rbs:
 	flushrs					// must be first in insn
-	;;
 	mov ar.rsc=r0				// put RSE into enforced lazy mode
 	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
-	mov r14=ar.rnat				// get rnat as updated by flushrs
 	;;
+	mov r14=ar.rnat				// get rnat as updated by flushrs
 	mov ar.bspstore=r15			// set new register backing store area
-	st8 [r16]=r14				// save sc_ar_rnat
 	;;
+	st8 [r16]=r14				// save sc_ar_rnat
 	mov ar.rsc=0xf				// set RSE into eager mode, pl 3
 	invala					// invalidate ALAT
 	br.cond.sptk.many back_from_setup_rbs
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/irq.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/irq.c	Fri Apr 21 15:21:24 2000
@@ -66,7 +66,7 @@
  * Controller mappings for all interrupt sources:
  */
 irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
-	{ [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
+	{ [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
 
 static void register_irq_proc (unsigned int irq);
 
@@ -164,7 +164,7 @@
 		p += sprintf(p, "%10u ",
 			atomic_read(&nmi_counter(cpu_logical_map(j))));
 	p += sprintf(p, "\n");
-#if CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(__i386__)
 	p += sprintf(p, "LOC: ");
 	for (j = 0; j < smp_num_cpus; j++)
 		p += sprintf(p, "%10u ",
@@ -182,8 +182,8 @@
  */
 
 #ifdef CONFIG_SMP
-unsigned char global_irq_holder = NO_PROC_ID;
-unsigned volatile int global_irq_lock;
+unsigned int global_irq_holder = NO_PROC_ID;
+volatile unsigned int global_irq_lock;
 
 extern void show_stack(unsigned long* esp);
 
@@ -201,6 +201,10 @@
 		printk(" %d",local_bh_count(i));
 
 	printk(" ]\nStack dumps:");
+#ifdef __ia64__
+	printk(" ]\nStack dumps: <unimplemented on IA-64---please fix me>");
+	/* for now we don't have stack dumping support... */
+#elif __i386__
 	for(i=0;i< smp_num_cpus;i++) {
 		unsigned long esp;
 		if(i==cpu)
@@ -219,8 +223,13 @@
 		esp += sizeof(struct task_struct);
 		show_stack((void*)esp);
  	}
+#else
+	You lose...
+#endif
 	printk("\nCPU %d:",cpu);
+#ifdef __i386__
 	show_stack(NULL);
+#endif
 	printk("\n");
 }
 	
@@ -250,7 +259,11 @@
 /*
  * We have to allow irqs to arrive between __sti and __cli
  */
-# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+# ifdef __ia64__
+#  define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop 0")
+# else
+#  define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+# endif
 #endif
 
 static inline void wait_on_irq(int cpu)
@@ -311,7 +324,7 @@
 {
 	if (test_and_set_bit(0,&global_irq_lock)) {
 		/* do we already hold the lock? */
-		if ((unsigned char) cpu == global_irq_holder)
+		if (cpu == global_irq_holder)
 			return;
 		/* Uhhuh.. Somebody else got it. Wait.. */
 		do {
@@ -349,6 +362,15 @@
 {
 	unsigned int flags;
 
+#ifdef __ia64__
+	__save_flags(flags);
+	if (flags & IA64_PSR_I) {
+		int cpu = smp_processor_id();
+		__cli();
+		if (!local_irq_count(cpu))
+			get_irqlock(cpu);
+	}
+#else
 	__save_flags(flags);
 	if (flags & (1 << EFLAGS_IF_SHIFT)) {
 		int cpu = smp_processor_id();
@@ -356,6 +378,7 @@
 		if (!local_irq_count(cpu))
 			get_irqlock(cpu);
 	}
+#endif
 }
 
 void __global_sti(void)
@@ -382,7 +405,11 @@
 	int cpu = smp_processor_id();
 
 	__save_flags(flags);
+#ifdef __ia64__
+	local_enabled = (flags & IA64_PSR_I) != 0;
+#else
 	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
+#endif
 	/* default to local */
 	retval = 2 + local_enabled;
 
@@ -479,11 +506,13 @@
 {
 	disable_irq_nosync(irq);
 
+#ifdef CONFIG_SMP
 	if (!local_irq_count(smp_processor_id())) {
 		do {
 			barrier();
 		} while (irq_desc[irq].status & IRQ_INPROGRESS);
 	}
+#endif
 }
 
 void enable_irq(unsigned int irq)
@@ -559,15 +588,12 @@
 
 	/*
 	 * If there is no IRQ handler or it was disabled, exit early.
-	   Since we set PENDING, if another processor is handling
-	   a different instance of this same irq, the other processor
-	   will take care of it.
+	 * Since we set PENDING, if another processor is handling
+	 * a different instance of this same irq, the other processor
+	 * will take care of it.
 	 */
 	if (!action)
-{
-	desc->status = status & ~IRQ_INPROGRESS;
 		goto out;
-}
 
 	/*
 	 * Edge triggered interrupts need to remember
@@ -597,15 +623,6 @@
 	desc->handler->end(irq);
 	spin_unlock(&desc->lock);
 
-#if 0
-	/*
-	 * let kernel exit path take care of this; we want to do the
-	 * CPU EOI before doing softirq() so a new interrupt can come
-	 * through
-	 */
-	if (softirq_state[cpu].active & softirq_state[cpu].mask)
-		do_softirq();
-#endif
 	return 1;
 }
 
@@ -1019,7 +1036,7 @@
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
 	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
 
 	entry->nlink = 1;
 	entry->data = (void *)(long)irq;
@@ -1040,7 +1057,7 @@
 	root_irq_dir = proc_mkdir("irq", 0);
 
 	/* create /proc/irq/prof_cpu_mask */
-	entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
 
 	entry->nlink = 1;
 	entry->data = (void *)&prof_cpu_mask;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/irq_ia64.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/irq_ia64.c	Fri Apr 21 15:21:24 2000
@@ -25,10 +25,6 @@
 #include <linux/smp_lock.h>
 #include <linux/threads.h>
 
-#ifdef CONFIG_KDB
-# include <linux/kdb.h>
-#endif
-
 #include <asm/bitops.h>
 #include <asm/delay.h>
 #include <asm/io.h>
@@ -41,13 +37,15 @@
 spinlock_t ivr_read_lock;
 #endif
 
+unsigned long ipi_base_addr = IPI_DEFAULT_BASE_ADDR;	/* default base addr of IPI table */
+
 /*
  * Legacy IRQ to IA-64 vector translation table.  Any vector not in
  * this table maps to itself (ie: irq 0x30 => IA64 vector 0x30)
  */
-__u8 isa_irq_to_vector_map[IA64_MIN_VECTORED_IRQ] = {
+__u8 isa_irq_to_vector_map[16] = {
 	/* 8259 IRQ translation, first 16 entries */
-	0x60, 0x50, 0x0f, 0x51, 0x52, 0x53, 0x43, 0x54,
+	0x60, 0x50, 0x10, 0x51, 0x52, 0x53, 0x43, 0x54,
 	0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x40, 0x41
 };
 
@@ -80,8 +78,8 @@
 #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
 # ifndef CONFIG_SMP
 	static unsigned int max_prio = 0;
-# endif
 	unsigned int prev_prio;
+# endif
 	unsigned long eoi_ptr;
  
 # ifdef CONFIG_USB
@@ -95,21 +93,25 @@
 	 * Stop IPIs by getting the ivr_read_lock
 	 */
 	spin_lock(&ivr_read_lock);
+	{
+		unsigned int tmp;
 
-	/*
-	 * Disable PCI writes
-	 */
-	outl(0x80ff81c0, 0xcf8);
-	outl(0x73002188, 0xcfc);
-	eoi_ptr = inl(0xcfc);
-
-	vector = ia64_get_ivr();
-
-	/*
-	 * Enable PCI writes
-	 */
-	outl(0x73182188, 0xcfc);
-
+		/*
+		 * Disable PCI writes
+		 */
+		outl(0x80ff81c0, 0xcf8);
+		tmp = inl(0xcfc);
+		outl(tmp | 0x400, 0xcfc);
+
+		eoi_ptr = inl(0xcfc);
+
+		vector = ia64_get_ivr();
+
+		/*
+		 * Enable PCI writes
+		 */
+		outl(tmp, 0xcfc);
+	}
 	spin_unlock(&ivr_read_lock);
 
 # ifdef CONFIG_USB
@@ -152,9 +154,6 @@
 			printk("ia64_handle_irq: DANGER: less than 1KB of free stack space!!\n"
 			       "(bsp=0x%lx, sp=%lx)\n", bsp, sp);
 		}
-#ifdef CONFIG_KDB
-		kdb(KDB_REASON_PANIC, 0, regs);
-#endif		
 	}
 
 	/*
@@ -175,9 +174,6 @@
 		if (!pEOI) {
 			printk("Yikes: ia64_handle_irq() without pEOI!!\n");
 			asm volatile ("cmp.eq p1,p0=r0,r0" : "=r"(pEOI));
-# ifdef CONFIG_KDB
-			kdb(KDB_REASON_PANIC, 0, regs);
-# endif
 		}
 	}
 
@@ -195,13 +191,13 @@
 
 #ifdef CONFIG_SMP
 
-void __init
-init_IRQ_SMP (void)
-{
-	if (request_irq(IPI_IRQ, handle_IPI, 0, "IPI", NULL))
-		panic("Could not allocate IPI Interrupt Handler!");
-}
+extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
 
+static struct irqaction ipi_irqaction = {
+	handler:	handle_IPI,
+	flags:		SA_INTERRUPT,
+	name:		"IPI"
+};
 #endif
 
 void __init
@@ -214,13 +210,14 @@
 	ia64_set_lrr0(0, 1);	
 	ia64_set_lrr1(0, 1);	
 
-	irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal;
+	irq_desc[TIMER_IRQ].handler	    = &irq_type_ia64_sapic;
+	irq_desc[IA64_SPURIOUS_INT].handler = &irq_type_ia64_sapic;
 #ifdef CONFIG_SMP
 	/* 
 	 * Configure the IPI vector and handler
 	 */
-	irq_desc[IPI_IRQ].handler = &irq_type_ia64_internal;
-	init_IRQ_SMP();
+	irq_desc[IPI_IRQ].handler = &irq_type_ia64_sapic;
+	setup_irq(IPI_IRQ, &ipi_irqaction);
 #endif
 
 	ia64_set_pmv(1 << 16);
@@ -232,16 +229,26 @@
 	ia64_set_tpr(0);
 }
 
-/* TBD:
- * 	Certain IA64 platforms can have inter-processor interrupt support.
- * 	This interface is supposed to default to the IA64 IPI block-based
- * 	mechanism if the platform doesn't provide a separate mechanism
- *	for IPIs.
- *	Choices : (1) Extend hw_interrupt_type interfaces 
- *		  (2) Use machine vector mechanism
- *	For now defining the following interface as a place holder.
- */
 void
-ipi_send (int cpu, int vector, int delivery_mode)
+ipi_send (int cpu, int vector, int delivery_mode, int redirect)
 {
+	unsigned long ipi_addr;
+	unsigned long ipi_data;
+#ifdef	CONFIG_ITANIUM_ASTEP_SPECIFIC
+	unsigned long flags;
+#endif
+#	define EID	0
+
+	ipi_data = (delivery_mode << 8) | (vector & 0xff);
+	ipi_addr = ipi_base_addr | ((cpu << 8 | EID) << 4) | ((redirect & 1)  << 3);
+
+#ifdef	CONFIG_ITANIUM_ASTEP_SPECIFIC
+	spin_lock_irqsave(&ivr_read_lock, flags);
+#endif	/* CONFIG_ITANIUM_ASTEP_SPECIFIC */
+
+	writeq(ipi_data, ipi_addr);
+
+#ifdef	CONFIG_ITANIUM_ASTEP_SPECIFIC
+	spin_unlock_irqrestore(&ivr_read_lock, flags);
+#endif
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_internal.c linux/arch/ia64/kernel/irq_internal.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/irq_internal.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/irq_internal.c	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-/*
- * Internal Interrupt Vectors 
- *
- * This takes care of interrupts that are generated by the CPU
- * internally, such as the ITC and IPI interrupts.
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 2000 Hewlett-Packard Co
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/irq.h>
-
-static unsigned int
-internal_noop_startup (unsigned int irq)
-{
-	return 0;
-}
-
-static void
-internal_noop (unsigned int irq)
-{
-	/* nuthing to do... */
-}
-
-struct hw_interrupt_type irq_type_ia64_internal = {
-	typename:	"IA64-internal",
-	startup:	internal_noop_startup,
-	shutdown:	internal_noop,
-	enable:		internal_noop,
-	disable:	internal_noop,
-	ack:		internal_noop,
-	end:		internal_noop,
-	set_affinity:	(void (*)(unsigned int, unsigned long)) internal_noop
-};
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_lock.c linux/arch/ia64/kernel/irq_lock.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/irq_lock.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/irq_lock.c	Wed Dec 31 16:00:00 1969
@@ -1,287 +0,0 @@
-/*
- * SMP IRQ Lock support
- *
- * Global interrupt locks for SMP. Allow interrupts to come in on any
- * CPU, yet make cli/sti act globally to protect critical regions..
- * These function usually appear in irq.c, but I think it's cleaner this way.
- * 
- * Copyright (C) 1999 VA Linux Systems 
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- */ 
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/bitops.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-
-int global_irq_holder = NO_PROC_ID;
-spinlock_t global_irq_lock;
-atomic_t global_irq_count;
-atomic_t global_bh_count;
-spinlock_t global_bh_lock;
-
-#define INIT_STUCK (1<<26)
-
-void
-irq_enter(int cpu, int irq)
-{
-        int stuck = INIT_STUCK;
-
-        hardirq_enter(cpu, irq);
-        barrier();
-        while (global_irq_lock.lock) {
-                if (cpu == global_irq_holder) {
-			break;
-                }
-
-		if (!--stuck) {
-			printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",
-			       irq, cpu,global_irq_holder);
-			stuck = INIT_STUCK;
-		}
-                barrier();
-        }
-}
-
-void
-irq_exit(int cpu, int irq)
-{
-        hardirq_exit(cpu, irq);
-        release_irqlock(cpu);
-}
-
-static void
-show(char * str)
-{
-        int i;
-        unsigned long *stack;
-        int cpu = smp_processor_id();
-
-        printk("\n%s, CPU %d:\n", str, cpu);
-        printk("irq:  %d [%d %d]\n",
-                atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
-        printk("bh:   %d [%d %d]\n",
-                atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
-
-        stack = (unsigned long *) &stack;
-        for (i = 40; i ; i--) {
-                unsigned long x = *++stack;
-                if (x > (unsigned long) &get_options && x < (unsigned long) &vsprintf) {
-                        printk("<[%08lx]> ", x);
-                }
-        }
-}
-        
-#define MAXCOUNT 100000000
-
-static inline void 
-wait_on_bh(void)
-{
-        int count = MAXCOUNT;
-        do {
-                if (!--count) {
-                        show("wait_on_bh");
-                        count = ~0;
-                }
-                /* nothing .. wait for the other bh's to go away */
-        } while (atomic_read(&global_bh_count) != 0);
-}
-
-static inline void 
-wait_on_irq(int cpu)
-{
-        int count = MAXCOUNT;
-
-        for (;;) {
-
-                /*
-                 * Wait until all interrupts are gone. Wait
-                 * for bottom half handlers unless we're
-                 * already executing in one..
-                 */
-                if (!atomic_read(&global_irq_count)) {
-                        if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
-                                break;
-                }
-
-                /* Duh, we have to loop. Release the lock to avoid deadlocks */
-		spin_unlock(&global_irq_lock);
-		mb();
-
-                for (;;) {
-                        if (!--count) {
-                                show("wait_on_irq");
-                                count = ~0;
-                        }
-                        __sti();
-                        udelay(cpu + 1);
-                        __cli();
-                        if (atomic_read(&global_irq_count))
-                                continue;
-                        if (global_irq_lock.lock)
-                                continue;
-                        if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
-                                continue;
-                        if (spin_trylock(&global_irq_lock))
-                                break;
-                }
-        }
-}
-
-/*
- * This is called when we want to synchronize with
- * bottom half handlers. We need to wait until
- * no other CPU is executing any bottom half handler.
- *
- * Don't wait if we're already running in an interrupt
- * context or are inside a bh handler. 
- */
-void 
-synchronize_bh(void)
-{
-        if (atomic_read(&global_bh_count)) {
-                int cpu = smp_processor_id();
-                if (!local_irq_count[cpu] && !local_bh_count[cpu]) {
-                        wait_on_bh();
-                }
-        }
-}
-
-
-/*
- * This is called when we want to synchronize with
- * interrupts. We may for example tell a device to
- * stop sending interrupts: but to make sure there
- * are no interrupts that are executing on another
- * CPU we need to call this function.
- */
-void 
-synchronize_irq(void)
-{
-        int cpu = smp_processor_id();
-        int local_count;
-        int global_count;
-
-        mb();
-        do {
-                local_count = local_irq_count[cpu];
-                global_count = atomic_read(&global_irq_count);
-        } while (global_count != local_count);
-}
-
-static inline void 
-get_irqlock(int cpu)
-{
-        if (!spin_trylock(&global_irq_lock)) {
-                /* do we already hold the lock? */
-                if ((unsigned char) cpu == global_irq_holder)
-                        return;
-                /* Uhhuh.. Somebody else got it. Wait.. */
-		spin_lock(&global_irq_lock);
-        }
-        /* 
-         * We also to make sure that nobody else is running
-         * in an interrupt context. 
-         */
-        wait_on_irq(cpu);
-
-        /*
-         * Ok, finally..
-         */
-        global_irq_holder = cpu;
-}
-
-/*
- * A global "cli()" while in an interrupt context
- * turns into just a local cli(). Interrupts
- * should use spinlocks for the (very unlikely)
- * case that they ever want to protect against
- * each other.
- *
- * If we already have local interrupts disabled,
- * this will not turn a local disable into a
- * global one (problems with spinlocks: this makes
- * save_flags+cli+sti usable inside a spinlock).
- */
-void 
-__global_cli(void)
-{
-	unsigned long flags;
-
-	__save_flags(flags);
-	if (flags & IA64_PSR_I) {
-		int cpu = smp_processor_id();
-		__cli();
-		if (!local_irq_count[cpu])
-			get_irqlock(cpu);
-	}
-}
-
-void 
-__global_sti(void)
-{
-        int cpu = smp_processor_id();
-
-        if (!local_irq_count[cpu])
-                release_irqlock(cpu);
-        __sti();
-}
-
-/*
- * SMP flags value to restore to:
- * 0 - global cli
- * 1 - global sti
- * 2 - local cli
- * 3 - local sti
- */
-unsigned long 
-__global_save_flags(void)
-{
-        int retval;
-        int local_enabled;
-        unsigned long flags;
-
-        __save_flags(flags);
-        local_enabled = flags & IA64_PSR_I;
-        /* default to local */
-        retval = 2 + local_enabled;
-
-        /* check for global flags if we're not in an interrupt */
-        if (!local_irq_count[smp_processor_id()]) {
-                if (local_enabled)
-                        retval = 1;
-                if (global_irq_holder == (unsigned char) smp_processor_id())
-                        retval = 0;
-        }
-        return retval;
-}
-
-void 
-__global_restore_flags(unsigned long flags)
-{
-        switch (flags) {
-        case 0:
-                __global_cli();
-                break;
-        case 1:
-                __global_sti();
-                break;
-        case 2:
-                __cli();
-                break;
-        case 3:
-                __sti();
-                break;
-        default:
-		printk("global_restore_flags: %08lx (%08lx) from %p\n",
-		       flags, (&flags)[-1], __builtin_return_address(0));
-        }
-}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_sapic.c linux/arch/ia64/kernel/irq_sapic.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/irq_sapic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/kernel/irq_sapic.c	Fri Apr 21 15:21:24 2000
@@ -0,0 +1,38 @@
+/*
+ * SAPIC Interrupt Controller
+ *
+ * This takes care of interrupts that are generated by the CPU's
+ * internal Streamlined Advanced Programmable Interrupt Controller
+ * (SAPIC), such as the ITC and IPI interrupts.
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+static unsigned int
+sapic_noop_startup (unsigned int irq)
+{
+	return 0;
+}
+
+static void
+sapic_noop (unsigned int irq)
+{
+	/* nuthing to do... */
+}
+
+struct hw_interrupt_type irq_type_ia64_sapic = {
+	typename:	"SAPIC",
+	startup:	sapic_noop_startup,
+	shutdown:	sapic_noop,
+	enable:		sapic_noop,
+	disable:	sapic_noop,
+	ack:		sapic_noop,
+	end:		sapic_noop,
+	set_affinity:	(void (*)(unsigned int, unsigned long)) sapic_noop
+};
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S
--- v2.3.99-pre5/linux/arch/ia64/kernel/ivt.S	Sat Feb 26 22:31:39 2000
+++ linux/arch/ia64/kernel/ivt.S	Fri Apr 21 15:21:24 2000
@@ -5,213 +5,6 @@
  * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 1998-2000 David Mosberger <davidm@hpl.hp.com>
  */
-
-#include <linux/config.h>
-
-#include <asm/break.h>
-#include <asm/offsets.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/system.h>
-#include <asm/unistd.h>
-
-#include "entry.h"
-
-/*
- * A couple of convenience macros that make writing and reading
- * SAVE_MIN and SAVE_REST easier.
- */
-#define rARPR		r31
-#define rCRIFS		r30
-#define rCRIPSR		r29
-#define rCRIIP		r28
-#define rARRSC		r27
-#define rARPFS		r26
-#define rARUNAT		r25
-#define rARRNAT		r24
-#define rARBSPSTORE	r23
-#define rKRBS		r22
-#define rB6		r21
-#define rR1		r20
-
-/*
- * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
- * the minimum state necessary that allows us to turn psr.ic back
- * on.
- *
- * Assumed state upon entry:
- *	psr.ic: off
- *	psr.dt: off
- *	r31:	contains saved predicates (pr)
- *
- * Upon exit, the state is as follows:
- *	psr.ic: off
- *	psr.dt: off
- *	r2 = points to &pt_regs.r16
- *	r12 = kernel sp (kernel virtual address)
- *	r13 = points to current task_struct (kernel virtual address)
- *	p15 = TRUE if psr.i is set in cr.ipsr
- *	predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15:
- *		preserved
- *
- * Note that psr.ic is NOT turned on by this macro.  This is so that
- * we can pass interruption state as arguments to a handler.
- */
-#define DO_SAVE_MIN(COVER,EXTRA)								  \
-	mov rARRSC=ar.rsc;									  \
-	mov rARPFS=ar.pfs;									  \
-	mov rR1=r1;										  \
-	mov rARUNAT=ar.unat;									  \
-	mov rCRIPSR=cr.ipsr;									  \
-	mov rB6=b6;		/* rB6 = branch reg 6 */					  \
-	mov rCRIIP=cr.iip;									  \
-	mov r1=ar.k6;		/* r1 = current */						  \
-	;;											  \
-	invala;											  \
-	extr.u r16=rCRIPSR,32,2;		/* extract psr.cpl */				  \
-	;;											  \
-	cmp.eq pKern,p7=r0,r16;			/* are we in kernel mode already? (psr.cpl==0) */ \
-	/* switch from user to kernel RBS: */							  \
-	COVER;											  \
-	;;											  \
-(p7)	mov ar.rsc=r0;		/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	  \
-(p7)	addl rKRBS=IA64_RBS_OFFSET,r1;		/* compute base of register backing store */	  \
-	;;											  \
-(p7)	mov rARRNAT=ar.rnat;									  \
-(pKern)	dep r1=0,sp,61,3;				/* compute physical addr of sp  */	  \
-(p7)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1;	/* compute base of memory stack */	  \
-(p7)	mov rARBSPSTORE=ar.bspstore;			/* save ar.bspstore */			  \
-(p7)	dep rKRBS=-1,rKRBS,61,3;			/* compute kernel virtual addr of RBS */  \
-	;;											  \
-(pKern)	addl r1=-IA64_PT_REGS_SIZE,r1;		/* if in kernel mode, use sp (r12) */		  \
-(p7)	mov ar.bspstore=rKRBS;			/* switch to kernel RBS */			  \
-	;;											  \
-(p7)	mov r18=ar.bsp;										  \
-(p7)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */		  \
-												  \
-	mov r16=r1;		/* initialize first base pointer */				  \
-	adds r17=8,r1;		/* initialize second base pointer */				  \
-	;;											  \
-	st8 [r16]=rCRIPSR,16;	/* save cr.ipsr */						  \
-	st8 [r17]=rCRIIP,16;	/* save cr.iip */						  \
-(pKern)	mov r18=r0;		/* make sure r18 isn't NaT */					  \
-	;;											  \
-	st8 [r16]=rCRIFS,16;	/* save cr.ifs */						  \
-	st8 [r17]=rARUNAT,16;	/* save ar.unat */						  \
-(p7)	sub r18=r18,rKRBS;	/* r18=RSE.ndirty*8 */						  \
-	;;											  \
-	st8 [r16]=rARPFS,16;	/* save ar.pfs */						  \
-	st8 [r17]=rARRSC,16;	/* save ar.rsc */						  \
-	tbit.nz p15,p0=rCRIPSR,IA64_PSR_I_BIT							  \
-	;;			/* avoid RAW on r16 & r17 */					  \
-(pKern)	adds r16=16,r16;	/* skip over ar_rnat field */					  \
-(pKern)	adds r17=16,r17;	/* skip over ar_bspstore field */				  \
-(p7)	st8 [r16]=rARRNAT,16;	/* save ar.rnat */						  \
-(p7)	st8 [r17]=rARBSPSTORE,16;	/* save ar.bspstore */					  \
-	;;											  \
-	st8 [r16]=rARPR,16;	/* save predicates */						  \
-	st8 [r17]=rB6,16;	/* save b6 */							  \
-	shl r18=r18,16;		/* compute ar.rsc to be used for "loadrs" */			  \
-	;;											  \
-	st8 [r16]=r18,16;	/* save ar.rsc value for "loadrs" */				  \
-	st8.spill [r17]=rR1,16;	/* save original r1 */						  \
-	cmp.ne pEOI,p0=r0,r0	/* clear pEOI by default */					  \
-	;;											  \
-	st8.spill [r16]=r2,16;									  \
-	st8.spill [r17]=r3,16;									  \
-	adds r2=IA64_PT_REGS_R16_OFFSET,r1;							  \
-	;;											  \
-	st8.spill [r16]=r12,16;									  \
-	st8.spill [r17]=r13,16;									  \
-	cmp.eq pNonSys,pSys=r0,r0	/* initialize pSys=0, pNonSys=1 */			  \
-	;;											  \
-	st8.spill [r16]=r14,16;									  \
-	st8.spill [r17]=r15,16;									  \
-	dep r14=-1,r0,61,3;									  \
-	;;											  \
-	st8.spill [r16]=r8,16;									  \
-	st8.spill [r17]=r9,16;									  \
-	adds r12=-16,r1;	/* switch to kernel memory stack (with 16 bytes of scratch) */	  \
-	;;											  \
-	st8.spill [r16]=r10,16;									  \
-	st8.spill [r17]=r11,16;									  \
-	mov r13=ar.k6;		/* establish `current' */					  \
-	;;											  \
-	or r2=r2,r14;		/* make first base a kernel virtual address */			  \
-	EXTRA;											  \
-	movl r1=__gp;		/* establish kernel global pointer */				  \
-	;;											  \
-	or r12=r12,r14;		/* make sp a kernel virtual address */				  \
-	or r13=r13,r14;		/* make `current' a kernel virtual address */			  \
-	bsw.1;;			/* switch back to bank 1 (must be last in insn group) */
-
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
-# define STOPS	nop.i 0x0;; nop.i 0x0;; nop.i 0x0;;
-#else
-# define STOPS
-#endif
-
-#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS
-#define SAVE_MIN_WITH_COVER_R19	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS
-#define SAVE_MIN		DO_SAVE_MIN(mov rCRIFS=r0,) STOPS
-
-/*
- * SAVE_REST saves the remainder of pt_regs (with psr.ic on).  This
- * macro guarantees to preserve all predicate registers, r8, r9, r10,
- * r11, r14, and r15.
- *
- * Assumed state upon entry:
- *	psr.ic: on
- *	psr.dt: on
- *	r2:	points to &pt_regs.r16
- *	r3:	points to &pt_regs.r17
- */
-#define SAVE_REST				\
-	st8.spill [r2]=r16,16;			\
-	st8.spill [r3]=r17,16;			\
-	;;					\
-	st8.spill [r2]=r18,16;			\
-	st8.spill [r3]=r19,16;			\
-	;;					\
-	mov r16=ar.ccv;		/* M-unit */	\
-	movl r18=FPSR_DEFAULT	/* L-unit */	\
-	;;					\
-	mov r17=ar.fpsr;	/* M-unit */	\
-	mov ar.fpsr=r18;	/* M-unit */	\
-	;;					\
-	st8.spill [r2]=r20,16;			\
-	st8.spill [r3]=r21,16;			\
-	mov r18=b0;				\
-	;;					\
-	st8.spill [r2]=r22,16;			\
-	st8.spill [r3]=r23,16;			\
-	mov r19=b7;				\
-	;;					\
-	st8.spill [r2]=r24,16;			\
-	st8.spill [r3]=r25,16;			\
-	;;					\
-	st8.spill [r2]=r26,16;			\
-	st8.spill [r3]=r27,16;			\
-	;;					\
-	st8.spill [r2]=r28,16;			\
-	st8.spill [r3]=r29,16;			\
-	;;					\
-	st8.spill [r2]=r30,16;			\
-	st8.spill [r3]=r31,16;			\
-	;;					\
-	st8 [r2]=r16,16;	/* ar.ccv */	\
-	st8 [r3]=r17,16;	/* ar.fpsr */	\
-	;;					\
-	st8 [r2]=r18,16;	/* b0 */	\
-	st8 [r3]=r19,16+8;	/* b7 */	\
-	;;					\
-	stf.spill [r2]=f6,32;			\
-	stf.spill [r3]=f7,32;			\
-	;;					\
-	stf.spill [r2]=f8,32;			\
-	stf.spill [r3]=f9,32
-
 /*
  * This file defines the interrupt vector table used by the CPU.
  * It does not include one entry per possible cause of interruption.
@@ -236,9 +29,29 @@
  * The table is 32KB in size and must be aligned on 32KB boundary.
  * (The CPU ignores the 15 lower bits of the address)
  *
- * Table is based upon EAS2.4 (June 1998)
+ * Table is based upon EAS2.6 (Oct 1999)
  */
 
+#include <linux/config.h>
+
+#include <asm/break.h>
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/unistd.h>
+
+#define MINSTATE_START_SAVE_MIN	/* no special action needed */
+#define MINSTATE_END_SAVE_MIN									\
+	or r2=r2,r14;		/* make first base a kernel virtual address */			\
+	or r12=r12,r14;		/* make sp a kernel virtual address */				\
+	or r13=r13,r14;		/* make `current' a kernel virtual address */			\
+	bsw.1;			/* switch back to bank 1 (must be last in insn group) */	\
+	;;
+
+#include "minstate.h"
+
 #define FAULT(n)									\
 	rsm psr.dt;			/* avoid nested faults due to TLB misses... */	\
 	;;										\
@@ -336,8 +149,8 @@
 (p7)	tbit.nz.unc p10,p11=r19,32		// is it an instruction TLB miss?
 	dep r17=0,r17,0,PAGE_SHIFT		// clear low bits to get page address
 	;;
-(p10)	itc.i r18;;	// insert the instruction TLB entry (EAS2.6: must be last in insn group!)
-(p11)	itc.d r18;;	// insert the data TLB entry (EAS2.6: must be last in insn group!)
+(p10)	itc.i r18				// insert the instruction TLB entry
+(p11)	itc.d r18				// insert the data TLB entry
 (p6)	br.spnt.few page_fault			// handle bad address/page not present (page fault)
 	mov cr.ifa=r21
 
@@ -346,9 +159,9 @@
 	// the exception deferral bit.
 	adds r16=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r17
 	;;
-(p7)	itc.d r16;;	// EAS2.6: must be last in insn group!
+(p7)	itc.d r16
 	mov pr=r31,-1				// restore predicate registers
-	rfi;;					// must be last insn in an insn group
+	rfi
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -395,11 +208,11 @@
 	;;
 (p7)	tbit.z p6,p7=r18,0			// page present bit cleared?
 	;;
-(p7)	itc.i r18;;	// insert the instruction TLB entry (EAS2.6: must be last in insn group!)
+(p7)	itc.i r18				// insert the instruction TLB entry
 (p6)	br.spnt.few page_fault			// handle bad address/page not present (page fault)
 	;;
 	mov pr=r31,-1				// restore predicate registers
-	rfi;;					// must be last insn in an insn group
+	rfi
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -446,11 +259,11 @@
 	;;
 (p7)	tbit.z p6,p7=r18,0			// page present bit cleared?
 	;;
-(p7)	itc.d r18;;	// insert the instruction TLB entry (EAS2.6: must be last in insn group!)
+(p7)	itc.d r18				// insert the instruction TLB entry
 (p6)	br.spnt.few page_fault			// handle bad address/page not present (page fault)
 	;;
 	mov pr=r31,-1				// restore predicate registers
-	rfi;;					// must be last insn in an insn group
+	rfi
 
 	//-----------------------------------------------------------------------------------
 	// call do_page_fault (predicates are in r31, psr.dt is off, r16 is faulting address)
@@ -468,10 +281,9 @@
 	;;
 	ssm psr.ic | psr.dt
 	;;
-	srlz.d					// guarantee that interrupt collection is enabled
-(p15)	ssm psr.i				// restore psr.i
+	srlz.i					// guarantee that interrupt collection is enabled
 	;;
-	srlz.i					// must precede "alloc"! (srlz.i implies srlz.d)
+(p15)	ssm psr.i				// restore psr.i
 	movl r14=ia64_leave_kernel
 	;;
 	alloc r15=ar.pfs,0,0,3,0		// must be first in insn group
@@ -491,15 +303,15 @@
 	movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX
 	;;
 	shr.u r18=r16,57	// move address bit 61 to bit 4
-	dep r16=0,r16,52,12	// clear top 12 bits of address
+	dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits
 	;;
 	andcm r18=0x10,r18	// bit 4=~address-bit(61)
 	dep r16=r17,r16,0,12	// insert PTE control bits into r16
 	;;
 	or r16=r16,r18		// set bit 4 (uncached) if the access was to region 6
 	;;
-	itc.i r16;;	// insert the TLB entry(EAS2.6: must be last in insn group!)
-	rfi;;			// must be last insn in an insn group
+	itc.i r16		// insert the TLB entry
+	rfi
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -508,15 +320,15 @@
 	movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW
 	;;
 	shr.u r18=r16,57	// move address bit 61 to bit 4
-	dep r16=0,r16,52,12	// clear top 12 bits of address
+	dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits
 	;;
 	andcm r18=0x10,r18	// bit 4=~address-bit(61)
 	dep r16=r17,r16,0,12	// insert PTE control bits into r16
 	;;
 	or r16=r16,r18		// set bit 4 (uncached) if the access was to region 6
 	;;
-	itc.d r16;;	// insert the TLB entry (EAS2.6: must be last in insn group!)
-	rfi;;			// must be last insn in an insn group
+	itc.d r16		// insert the TLB entry
+	rfi
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -609,27 +421,31 @@
 	mov b0=r29				// restore b0
 	;;
 	st8 [r17]=r18				// store back updated PTE
-	itc.d r18;;		// install updated PTE (EAS2.6: must be last in insn group!)
-	rfi;;					// must be last insn in an insn group
+	itc.d r18				// install updated PTE
+	rfi
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27)
 	// Like Entry 8, except for instruction access
 	mov r16=cr.ifa				// get the address that caused the fault
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+#ifdef CONFIG_ITANIUM
+	/*
+	 * Erratum 10 (IFA may contain incorrect address) now has
+	 * "NoFix" status.  There are no plans for fixing this.
+	 */
+	mov r17=cr.ipsr
 	mov r31=pr				// save predicates
-	mov r30=cr.ipsr
 	;;
-	extr.u r17=r30,IA64_PSR_IS_BIT,1	// get instruction arch. indicator
+	mov r18=cr.iip
+	tbit.z p6,p0=r17,IA64_PSR_IS_BIT	// IA64 instruction set?
 	;;
-	cmp.eq p6,p0 = r17,r0			// check if IA64 instruction set
+(p6)	mov r16=r18				// if so, use cr.iip instead of cr.ifa
+#if 0
 	;;
-(p6)	mov r16=cr.iip				// get real faulting address
-	;;
-(p6)	mov cr.ifa=r16				// reset IFA
+#endif
 	mov pr=r31,-1
-#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
+#endif /* CONFIG_ITANIUM */
 	movl r30=1f				// load continuation point in case of nested fault
 	;;
 	thash r17=r16				// compute virtual address of L3 PTE
@@ -641,8 +457,8 @@
 	mov b0=r29				// restore b0
 	;;
 	st8 [r17]=r18				// store back updated PTE
-	itc.i r18;;		// install updated PTE (EAS2.6: must be last in insn group!)
-	rfi;;					// must be last insn in an insn group
+	itc.i r18				// install updated PTE
+	rfi
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -660,8 +476,8 @@
 	mov b0=r29				// restore b0
 	;;
 	st8 [r17]=r18				// store back updated PTE
-	itc.d r18;;		// install updated PTE (EAS2.6: must be last in insn group!)
-	rfi;;					// must be last insn in an insn group
+	itc.d r18				// install updated PTE
+	rfi
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -689,12 +505,11 @@
 
 	// turn interrupt collection and data translation back on:
 	ssm psr.ic | psr.dt
-	srlz.d					// guarantee that interrupt collection is enabled
+	;;
+	srlz.i					// guarantee that interrupt collection is enabled
 	cmp.eq pSys,pNonSys=r0,r0		// set pSys=1, pNonSys=0
 	;;
 (p15)	ssm psr.i		// restore psr.i
-	;;
-	srlz.i			// ensure everybody knows psr.ic and psr.dt are back on
 	adds r8=(IA64_PT_REGS_R8_OFFSET-IA64_PT_REGS_R16_OFFSET),r2
 	;;
 	stf8 [r8]=f1		// ensure pt_regs.r8 != 0 (see handle_syscall_error)
@@ -813,11 +628,10 @@
 	;;
 	mov r14=cr.isr
 	ssm psr.ic | psr.dt
-	srlz.d					// guarantee that interrupt collection is enabled
 	;;
-(p15)	ssm psr.i
+	srlz.i					// guarantee that interrupt collection is enabled
 	;;
-	srlz.d
+(p15)	ssm psr.i
 	adds r3=8,r2            // Base pointer for SAVE_REST
 	;;
 	SAVE_REST
@@ -858,12 +672,13 @@
 	ld8 r16=[r16]
 	tbit.z p8,p0=r2,5	// (current->flags & PF_TRACESYS) == 0?
 	;;
-	movl r15=ia32_ret_from_syscall
 	mov b6=r16
+	movl r15=ia32_ret_from_syscall
 	;;
 	mov rp=r15
-(p8)	br.call.sptk.few b6=b6
-	br.call.sptk.few rp=ia32_trace_syscall	// rp will be overwritten (ignored)
+(p8)	br.call.sptk.many b6=b6
+	;;
+	br.call.sptk.many rp=ia32_trace_syscall	// rp will be overwritten (ignored)
 
 non_ia32_syscall:       
 	alloc r15=ar.pfs,0,0,2,0
@@ -885,13 +700,6 @@
 	FAULT(17)
 
 non_syscall:
-
-#ifdef CONFIG_KDB
-	mov r17=__IA64_BREAK_KDB
-	;;
-	cmp.eq p8,p0=r16,r17		// is this a kernel breakpoint?
-#endif
-
 	SAVE_MIN_WITH_COVER
 
 	// There is no particular reason for this code to be here, other than that
@@ -904,11 +712,10 @@
 
 	// turn interrupt collection and data translation back on:
 	ssm psr.ic | psr.dt
-	srlz.d					// guarantee that interrupt collection is enabled
 	;;
-(p15)	ssm psr.i			// restore psr.i
+	srlz.i				// guarantee that interrupt collection is enabled
 	;;
-	srlz.i				// ensure everybody knows psr.ic and psr.dt are back on
+(p15)	ssm psr.i			// restore psr.i
 	movl r15=ia64_leave_kernel
 	;;
 	alloc r14=ar.pfs,0,0,2,0
@@ -918,9 +725,6 @@
 	SAVE_REST
 	mov rp=r15
 	;;
-#ifdef CONFIG_KDB
-(p8)	br.call.sptk.few b6=ia64_invoke_kdb
-#endif
 	br.call.sptk.few b6=ia64_bad_break	// avoid WAW on CFM and ignore return addr
 
 	.align 1024
@@ -945,11 +749,10 @@
 	//
 	mov r15=cr.ifa
 	ssm psr.ic | psr.dt
-	srlz.d					// guarantee that interrupt collection is enabled
 	;;
-(p15)	ssm psr.i				// restore psr.i
+	srlz.i					// guarantee that interrupt collection is enabled
 	;;
-	srlz.i
+(p15)	ssm psr.i				// restore psr.i
 	adds r3=8,r2				// set up second base pointer
 	;;
 	SAVE_REST
@@ -994,13 +797,12 @@
 	mov r11=cr.itir
 	;;
 	ssm psr.ic | psr.dt
-	srlz.d					// guarantee that interrupt collection is enabled
+	;;
+	srlz.i					// guarantee that interrupt collection is enabled
 	;;
 (p15)	ssm psr.i				// restore psr.i
 	adds r3=8,r2				// set up second base pointer for SAVE_REST
 	;;
-	srlz.i					// must precede "alloc"!
-	;;
 	alloc r14=ar.pfs,0,0,5,0		// must be first in insn group
 	mov out0=r15
 	mov out1=r8
@@ -1012,11 +814,7 @@
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
-#ifdef CONFIG_KDB
-	br.call.sptk.few b6=ia64_invoke_kdb_fault_handler
-#else
 	br.call.sptk.few b6=ia64_fault
-#endif
 //
 // --- End of long entries, Beginning of short entries
 //
@@ -1121,7 +919,7 @@
 	mov cr.ipsr=r16
 	;;
 
-	rfi;;				// and go back (must be last insn in group)
+	rfi				// and go back
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -1142,11 +940,7 @@
 	;;									
 	srlz.d			// ensure everyone knows psr.dt is off
 	mov r19=30		// error vector for fault_handler (when kernel)
-	extr.u r16=r16,32,2	// extract psr.cpl
-	;;
-	cmp.eq p6,p7=r0,r16	// if kernel cpl then fault else emulate
-(p7)	br.cond.sptk.many dispatch_unaligned_handler
-(p6)	br.cond.sptk.many dispatch_to_fault_handler
+	br.cond.sptk.many dispatch_unaligned_handler
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -1226,6 +1020,31 @@
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept  (30,31,59,70,71)
+#ifdef	CONFIG_IA32_SUPPORT
+	rsm psr.dt
+	;;
+	srlz.d
+	mov r31=pr
+	mov r16=cr.isr
+	;;
+	extr.u r17=r16,16,8	// get ISR.code
+	mov r18=ar.eflag
+	mov r19=cr.iim		// old eflag value
+	;;
+	cmp.ne p2,p0=2,r17
+(p2)	br.cond.spnt 1f		// not a system flag fault
+	xor r16=r18,r19
+	;;
+	extr.u r17=r16,18,1	// get the eflags.ac bit
+	;;
+	cmp.eq p2,p0=0,r17
+(p2)	br.cond.spnt 1f		// eflags.ac bit didn't change
+	;;
+	mov pr=r31,-1		// restore predicate registers
+	rfi
+
+1:
+#endif	// CONFIG_IA32_SUPPORT
 	FAULT(46)
 
 	.align 256
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/mca.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/mca.c	Fri Apr 21 16:37:25 2000
@@ -2,21 +2,37 @@
  * File: 	mca.c
  * Purpose: 	Generic MCA handling layer
  *
+ * Updated for latest kernel
+ * Copyright (C) 2000 Intel
+ * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
+ *  
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
+ *
+ * 00/03/29 C. Fleckenstein  Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, 
+ *                           added min save state dump, added INIT handler. 
  */
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/smp_lock.h>
+#include <linux/config.h>
+
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/sal.h>
 #include <asm/mca.h>
-#include <asm/spinlock.h>
+
 #include <asm/irq.h>
 #include <asm/machvec.h>
 
+ 
+typedef struct ia64_fptr {
+	unsigned long fp;
+	unsigned long gp;
+} ia64_fptr_t;
 
 ia64_mc_info_t			ia64_mc_info;
 ia64_mca_sal_to_os_state_t	ia64_sal_to_os_handoff_state;
@@ -25,6 +41,11 @@
 u64				ia64_mca_stack[1024];
 u64				ia64_mca_stackframe[32];
 u64				ia64_mca_bspstore[1024];
+u64				ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
+
+#if defined(SAL_MPINIT_WORKAROUND) && !defined(CONFIG_SMP)
+int bootstrap_processor = -1;
+#endif
 
 static void			ia64_mca_cmc_vector_setup(int 		enable, 
 							  int_vector_t 	cmc_vector);
@@ -34,8 +55,99 @@
 static void			ia64_log_init(int,int);
 static void			ia64_log_get(int,int, prfunc_t);
 static void			ia64_log_clear(int,int,int, prfunc_t);
+extern void		        ia64_monarch_init_handler (void);
+extern void		        ia64_slave_init_handler (void);
+
+/*
+ * hack for now, add platform dependent handlers
+ * here
+ */
+#ifndef PLATFORM_MCA_HANDLERS
+void
+mca_handler_platform (void)
+{
+
+}
+
+void
+cmci_handler_platform (int cmc_irq, void *arg, struct pt_regs *ptregs)
+{
+
+}
+/*
+ * This routine will be used to deal with platform specific handling
+ * of the init, i.e. drop into the kernel debugger on server machine,
+ * or if the processor is part of some parallel machine without a
+ * console, then we would call the appropriate debug hooks here.
+ */
+void
+init_handler_platform (struct pt_regs *regs) 
+{
+	/* if a kernel debugger is available call it here else just dump the registers */
+	show_regs(regs);		/* dump the state info */
+}
+
+void
+log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc)
+{
+}
+	
+void
+ia64_mca_init_platform (void)
+{
+}
+
+#endif /* PLATFORM_MCA_HANDLERS */
+
+static char *min_state_labels[] = {
+	"nat",
+	"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
+	"r9", "r10","r11", "r12","r13","r14", "r15",
+	"b0r16","b0r17", "b0r18", "b0r19", "b0r20",
+	"b0r21", "b0r22","b0r23", "b0r24", "b0r25",
+	"b0r26", "b0r27", "b0r28","b0r29", "b0r30", "b0r31",
+	"r16", "r17", "r18","r19", "r20", "r21","r22",
+	"r23", "r24","r25", "r26", "r27","r28", "r29", "r30","r31",
+	"preds", "br0", "rsc",
+	"iip", "ipsr", "ifs",
+	"xip", "xpsr", "xfs"
+};
+
+int ia64_pmss_dump_bank0=0;  /* dump bank 0 ? */
 
 /*
+ * routine to process and prepare to dump min_state_save
+ * information for debugging purposes.
+ *
+ */
+void
+ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs)
+{
+	int i, max=57;
+	u64 *tpmss_ptr=(u64 *)pmss;
+
+	/* dump out the min_state_area information */
+
+	for (i=0;i<max;i++) {
+
+		if(!ia64_pmss_dump_bank0) {
+			if(strncmp("B0",min_state_labels[i],2)==0) {
+				tpmss_ptr++;  /* skip to next entry */
+				continue;
+			}
+		} 
+
+		printk("%5s=0x%16.16lx ",min_state_labels[i],*tpmss_ptr++);
+
+		if (((i+1)%3)==0 || ((!strcmp("GR16",min_state_labels[i]))
+				     && !ia64_pmss_dump_bank0))
+			printk("\n");
+	}
+	/* hang city for now, until we include debugger or copy to ptregs to show: */
+	while (1);
+}
+ 
+/*
  * ia64_mca_cmc_vector_setup
  *	Setup the correctable machine check vector register in the processor
  * Inputs
@@ -83,7 +195,7 @@
 #endif /* #if defined(MCA_TEST) */
 
 /*
- * mca_init
+ * ia64_mca_init
  *	Do all the mca specific initialization on a per-processor basis.
  *
  *	1. Register spinloop and wakeup request interrupt vectors
@@ -93,7 +205,7 @@
  *	3. Register OS_INIT handler entry point
  *
  *	4. Initialize CMCV register to enable/disable CMC interrupt on the
- *	   processor and hook a handler in the platform-specific mca_init.
+ *	   processor and hook a handler in the platform-specific ia64_mca_init.
  *
  *	5. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
  *
@@ -103,11 +215,20 @@
  *	None
  */
 void __init
-mca_init(void)
+ia64_mca_init(void)
 {
-	int	i;
+	ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler;
+	ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler;
+	int i;
+
+	IA64_MCA_DEBUG("ia64_mca_init : begin\n");
+
+#if defined(SAL_MPINIT_WORKAROUND) && !defined(CONFIG_SMP)
+	/* XXX -- workaround for SAL bug for running on MP system, but UP kernel */
+
+	bootstrap_processor = hard_smp_processor_id();
+#endif
 
-	MCA_DEBUG("mca_init : begin\n");
 	/* Clear the Rendez checkin flag for all cpus */
 	for(i = 0 ; i < IA64_MAXCPUS; i++)
 		ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
@@ -134,14 +255,14 @@
 				   0))
 		return;
 
-	MCA_DEBUG("mca_init : registered mca rendezvous spinloop and wakeup mech.\n");
+	IA64_MCA_DEBUG("ia64_mca_init : registered mca rendezvous spinloop and wakeup mech.\n");
 	/*
 	 * Setup the correctable machine check vector
 	 */
 	ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, 
 				  IA64_MCA_CMC_INT_VECTOR);
 
-	MCA_DEBUG("mca_init : correctable mca vector setup done\n");
+	IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n");
 
 	ia64_mc_info.imi_mca_handler 		= __pa(ia64_os_mca_dispatch);
 	ia64_mc_info.imi_mca_handler_size	= 
@@ -155,12 +276,15 @@
 
 		return;
 
-	MCA_DEBUG("mca_init : registered os mca handler with SAL\n");
+	IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n");
 
-	ia64_mc_info.imi_monarch_init_handler 		= __pa(ia64_monarch_init_handler);
+	ia64_mc_info.imi_monarch_init_handler 		= __pa(mon_init_ptr->fp);
 	ia64_mc_info.imi_monarch_init_handler_size	= IA64_INIT_HANDLER_SIZE;
-	ia64_mc_info.imi_slave_init_handler 		= __pa(ia64_slave_init_handler);
+	ia64_mc_info.imi_slave_init_handler 		= __pa(slave_init_ptr->fp);
 	ia64_mc_info.imi_slave_init_handler_size	= IA64_INIT_HANDLER_SIZE;
+
+	IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler);
+
 	/* Register the os init handler with SAL */
 	if (ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
 				 ia64_mc_info.imi_monarch_init_handler,
@@ -173,7 +297,7 @@
 
 		return;
 
-	MCA_DEBUG("mca_init : registered os init handler with SAL\n");
+	IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n");
 
 	/* Initialize the areas set aside by the OS to buffer the 
 	 * platform/processor error states for MCA/INIT/CMC
@@ -186,9 +310,9 @@
 	ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR);
 	ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM);
 
-	mca_init_platform();
+	ia64_mca_init_platform();
 	
-	MCA_DEBUG("mca_init : platform-specific mca handling setup done\n");
+	IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n");
 
 #if defined(MCA_TEST)
 	mca_test();
@@ -244,7 +368,7 @@
 void
 ia64_mca_wakeup(int cpu)
 {
-	ipi_send(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT);
+	ipi_send(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0);
 	ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
 	
 }
@@ -396,25 +520,6 @@
 	ia64_return_to_sal_check();
 }
 
-/*
- * SAL to OS entry point for INIT on the monarch processor
- * This has been defined for registration purposes with SAL 
- * as a part of mca_init.
- */
-void
-ia64_monarch_init_handler()
-{
-}
-/*
- * SAL to OS entry point for INIT on the slave processor
- * This has been defined for registration purposes with SAL 
- * as a part of mca_init.
- */
-
-void
-ia64_slave_init_handler()
-{
-}
 /* 
  * ia64_mca_cmc_int_handler
  *	This is correctable machine check interrupt handler.
@@ -450,10 +555,9 @@
 #define IA64_MAX_LOG_SUBTYPES	2	/* Processor, Platform */
 
 typedef struct ia64_state_log_s {
-	spinlock_t		isl_lock;
-	int			isl_index;
-	sal_log_header_t	isl_log[IA64_MAX_LOGS];
-
+	spinlock_t	isl_lock;
+	int		isl_index;
+	ia64_psilog_t	isl_log[IA64_MAX_LOGS];	/* need space to store header + error log */
 } ia64_state_log_t;
 
 static ia64_state_log_t	ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES];
@@ -472,6 +576,53 @@
 #define IA64_LOG_CURR_BUFFER(it, sit) 	(void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)]))
 
 /*
+ * C portion of the OS INIT handler
+ *
+ * Called from ia64_<monarch/slave>_init_handler
+ *
+ * Inputs: pointer to pt_regs where processor info was saved.
+ *
+ * Returns: 
+ *   0 if SAL must warm boot the System
+ *   1 if SAL must retrun to interrupted context using PAL_MC_RESUME
+ *
+ */
+
+void
+ia64_init_handler (struct pt_regs *regs)
+{
+	sal_log_processor_info_t *proc_ptr;
+	ia64_psilog_t *plog_ptr;
+
+	printk("Entered OS INIT handler\n");
+
+	/* Get the INIT processor log */
+	ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+	/* Get the INIT platform log */
+	ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk);
+
+#ifdef IA64_DUMP_ALL_PROC_INFO 
+	ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+#endif 
+
+	/* 
+	 * get pointer to min state save area
+	 *
+	 */
+	plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT,
+						       SAL_SUB_INFO_TYPE_PROCESSOR);
+	proc_ptr = &plog_ptr->devlog.proclog;
+	
+	ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs);
+
+	init_handler_platform(regs);              /* call platform specific routines */
+
+	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
+	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR);
+	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM);
+}
+
+/*
  * ia64_log_init
  * 	Reset the OS ia64 log buffer
  * Inputs 	:	info_type 	(SAL_INFO_TYPE_{MCA,INIT,CMC})
@@ -484,7 +635,7 @@
 	IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type);
 	IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0;
 	memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, 
-	       sizeof(sal_log_header_t) * IA64_MAX_LOGS);
+	       sizeof(ia64_psilog_t) * IA64_MAX_LOGS);
 }
 
 /* 
@@ -499,7 +650,7 @@
 ia64_log_get(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc)
 {
 	sal_log_header_t	*log_buffer;
-	int			s;
+	int			s,total_len=0;
 
 	IA64_LOG_LOCK(sal_info_type, sal_sub_info_type);
 
@@ -507,9 +658,11 @@
 	/* Get the process state information */
 	log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type);
 
-	if (ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer))
+	if (!(total_len=ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer)))
 		prfunc("ia64_mca_log_get : Getting processor log failed\n");
 
+	IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len);
+
 	IA64_LOG_INDEX_INC(sal_info_type, sal_sub_info_type);
 
 	IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type);
@@ -542,7 +695,7 @@
 		/* Get the process state information */
 		log_buffer = IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type);
 
-		memset(log_buffer, 0, sizeof(sal_log_header_t));
+		memset(log_buffer, 0, sizeof(ia64_psilog_t));
 
 		IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type);
 	
@@ -731,11 +884,7 @@
 	if (lh->slh_log_type != SAL_SUB_INFO_TYPE_PROCESSOR)
 		return;
 
-#if defined(MCA_TEST)
-	slpi = &slpi_buf;
-#else
-	slpi = (sal_log_processor_info_t *)lh->slh_log_dev_spec_info;
-#endif /#if defined(MCA_TEST) */
+	slpi = (sal_log_processor_info_t *)((char *)lh+sizeof(sal_log_header_t));  /* point to proc info */
 
 	if (!slpi) {
 		prfunc("No Processor Error Log found\n");
@@ -761,14 +910,6 @@
 	/* Print floating-point register contents if valid */
 	if (slpi->slpi_valid.slpi_fr) 
 		ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", 
-					      prfunc);
-
-	/* Print bank1-gr NAT register contents if valid */
-	ia64_log_processor_regs_print(&slpi->slpi_bank1_nat_bits, 1, "NAT", "nat", prfunc);
-
-	/* Print bank 1 register contents if valid */
-	if (slpi->slpi_valid.slpi_bank1_gr) 
-		ia64_log_processor_regs_print(slpi->slpi_bank1_gr, 16, "Bank1-General", "gr",
 					      prfunc);
 
 	/* Print the cache check information if any*/
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S
--- v2.3.99-pre5/linux/arch/ia64/kernel/mca_asm.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/mca_asm.S	Fri Apr 21 15:21:24 2000
@@ -1,7 +1,31 @@
+// 
+// assembly portion of the IA64 MCA handling
+//
+// Mods by cfleck to integrate into kernel build
+// 00/03/15 davidm Added various stop bits to get a clean compile
+// 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp kstack,
+//		   switch modes, jump to C INIT handler
+//
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
-#include <asm/mcaasm.h>
-#include <asm/page.h>
+#include <asm/mca_asm.h>
 #include <asm/mca.h>
+
+/*
+ * When we get an machine check, the kernel stack pointer is no longer
+ * valid, so we need to set a new stack pointer.
+ */
+#define MINSTATE_START_SAVE_MIN							\
+(pKern) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE;		\
+	;;
+
+#define MINSTATE_END_SAVE_MIN							\
+	or r12=r12,r14;		/* make sp a kernel virtual address */		\
+	or r13=r13,r14;		/* make `current' a kernel virtual address */	\
+	;;
+
+#include "minstate.h"
 	
 	.psr abi64
 	.psr lsb
@@ -54,7 +78,9 @@
 100:	(p)	mov		temp=ip;		\
 		;;					\
 	(p)	adds		temp=to_label-100b,temp;\
+		;;					\
 	(p)	adds		temp=adjust,temp;	\
+		;;					\
 	(p)	mov		b1=temp	;		\
 	(p)	br		b1	
 
@@ -68,6 +94,7 @@
 	.global	ia64_mca_stack
 	.global	ia64_mca_stackframe
 	.global	ia64_mca_bspstore
+	.global ia64_init_stack	
 			
 	.text
 	.align 16
@@ -341,6 +368,7 @@
         mov		r3=ar16                     // ar.rsc
 	mov		ar16=r0			    // put RSE in enforced lazy mode
         mov		r5=ar17                     // ar.bsp
+	;;
         mov		r7=ar18;;                   // ar.bspstore
         st8		[r2]=r3,3*8
         st8		[r4]=r5,3*8
@@ -575,6 +603,7 @@
 //      mov		ar16=r3                     // ar.rsc
 //      mov		ar17=r5                     // ar.bsp is read only
 	mov		ar16=r0			    // make sure that RSE is in enforced lazy mode
+	;;
         mov		ar18=r7;;                   // ar.bspstore
 
         ld8		r9=[r2],8*13;;
@@ -619,3 +648,146 @@
 	BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20)
 	;; 
 //EndStub//////////////////////////////////////////////////////////////////////
+
+// ok, the issue here is that we need to save state information so
+// it can be useable by the kernel debugger and show regs routines.
+// In order to do this, our best bet is save the current state (plus
+// the state information obtain from the MIN_STATE_AREA) into a pt_regs
+// format.  This way we can pass it on in a useable format.
+//				
+
+//
+// SAL to OS entry point for INIT on the monarch processor
+// This has been defined for registration purposes with SAL 
+// as a part of ia64_mca_init.
+//
+// When we get here, the follow registers have been
+// set by the SAL for our use
+//		
+//		1. GR1 = OS INIT GP
+//		2. GR8 = PAL_PROC physical address
+//		3. GR9 = SAL_PROC physical address
+//		4. GR10 = SAL GP (physical)
+//		5. GR11 = Init Reason
+//			0 = Received INIT for event other than crash dump switch
+//			1 = Received wakeup at the end of an OS_MCA corrected machine check
+//			2 = Received INIT dude to CrashDump switch assertion
+//	
+//		6. GR12 = Return address to location within SAL_INIT procedure
+
+				
+	.text
+	.align 16
+.global ia64_monarch_init_handler       
+.proc ia64_monarch_init_handler       
+ia64_monarch_init_handler:
+
+#if defined(SAL_MPINIT_WORKAROUND)
+	//
+	// work around SAL bug that sends all processors to monarch entry
+	//
+	.global bootstrap_processor
+
+	movl	r21=24
+	movl	r20=16
+	mov	r17=cr.lid
+	movl	r18=bootstrap_processor
+	;;
+	dep	r18=0,r18,61,3		// convert bsp to physical address
+	;;
+	shr	r19=r17,r20
+	shr	r22=r17,r21
+	ld4	r18=[r18]		// get the BSP ID
+	;;
+	and	r19=0xf, r19
+	and	r22=0xf, r22
+	;;
+	shl	r19=r19,8		// get them in the right order
+	;;
+	or	r22=r22,r19		// combine EID and LID
+	;;
+	cmp.eq	p6,p7=r22,r18		// Am I the BSP ?
+(p7)	br.cond.spnt slave_init_spin_me
+	;;
+#endif
+
+	
+//
+// ok, the first thing we do is stash the information
+// the SAL passed to os
+//
+_tmp = r2
+	movl	_tmp=ia64_sal_to_os_handoff_state
+	;;
+	dep	_tmp=0,_tmp, 61, 3	// get physical address
+	;;
+	st8	[_tmp]=r1,0x08;;
+	st8	[_tmp]=r8,0x08;;
+	st8	[_tmp]=r9,0x08;;			
+	st8	[_tmp]=r10,0x08;;			
+	st8	[_tmp]=r11,0x08;;
+	st8	[_tmp]=r12,0x08;;
+
+// now we want to save information so we can dump registers
+	SAVE_MIN_WITH_COVER
+	;;
+	mov r8=cr.ifa
+	mov r9=cr.isr
+	adds r3=8,r2				// set up second base pointer
+	;;
+	SAVE_REST
+	
+// ok, enough should be saved at this point to be dangerous, and  supply
+// information for a dump
+// We need to switch to Virtual mode before hitting the C functions.
+//
+// 
+//
+	movl	r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN
+	mov	r3=psr	// get the current psr, minimum enabled at this point
+	;;
+	or	r2=r2,r3
+	;;
+	movl	r3=IVirtual_Switch
+	;;
+	mov	cr.iip=r3		// short return to set the appropriate bits
+	mov	cr.ipsr=r2		// need to do an rfi to set appropriate bits
+	;;
+	rfi
+	;;
+IVirtual_Switch:
+	//	
+	// We should now be running virtual
+	//
+	// Lets call the C handler to get the rest of the state info
+	//
+	alloc r14=ar.pfs,0,0,1,0		// now it's safe (must be first in insn group!)
+	;;					//
+	adds out0=16,sp				// out0 = pointer to pt_regs
+	;;
+
+	br.call.sptk.few rp=ia64_init_handler
+	;;
+
+return_from_init:
+	br.sptk return_from_init
+
+	.endp
+
+//
+// SAL to OS entry point for INIT on the slave processor
+// This has been defined for registration purposes with SAL 
+// as a part of ia64_mca_init.
+//
+
+	.text
+	.align 16
+.global ia64_slave_init_handler
+.proc ia64_slave_init_handler
+ia64_slave_init_handler:		
+
+
+slave_init_spin_me:	
+	br.sptk slave_init_spin_me
+	;;
+	.endp
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/minstate.h linux/arch/ia64/kernel/minstate.h
--- v2.3.99-pre5/linux/arch/ia64/kernel/minstate.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/kernel/minstate.h	Fri Apr 21 15:21:24 2000
@@ -0,0 +1,205 @@
+#include <linux/config.h>
+
+#include "entry.h"
+
+/*
+ * A couple of convenience macros that make writing and reading
+ * SAVE_MIN and SAVE_REST easier.
+ */
+#define rARPR		r31
+#define rCRIFS		r30
+#define rCRIPSR		r29
+#define rCRIIP		r28
+#define rARRSC		r27
+#define rARPFS		r26
+#define rARUNAT		r25
+#define rARRNAT		r24
+#define rARBSPSTORE	r23
+#define rKRBS		r22
+#define rB6		r21
+#define rR1		r20
+
+/*
+ * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
+ * the minimum state necessary that allows us to turn psr.ic back
+ * on.
+ *
+ * Assumed state upon entry:
+ *	psr.ic: off
+ *	psr.dt: off
+ *	r31:	contains saved predicates (pr)
+ *
+ * Upon exit, the state is as follows:
+ *	psr.ic: off
+ *	psr.dt: off
+ *	r2 = points to &pt_regs.r16
+ *	r12 = kernel sp (kernel virtual address)
+ *	r13 = points to current task_struct (kernel virtual address)
+ *	p15 = TRUE if psr.i is set in cr.ipsr
+ *	predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15:
+ *		preserved
+ *
+ * Note that psr.ic is NOT turned on by this macro.  This is so that
+ * we can pass interruption state as arguments to a handler.
+ */
+#define DO_SAVE_MIN(COVER,EXTRA)								  \
+	mov rARRSC=ar.rsc;									  \
+	mov rARPFS=ar.pfs;									  \
+	mov rR1=r1;										  \
+	mov rARUNAT=ar.unat;									  \
+	mov rCRIPSR=cr.ipsr;									  \
+	mov rB6=b6;		/* rB6 = branch reg 6 */					  \
+	mov rCRIIP=cr.iip;									  \
+	mov r1=ar.k6;		/* r1 = current */						  \
+	;;											  \
+	invala;											  \
+	extr.u r16=rCRIPSR,32,2;		/* extract psr.cpl */				  \
+	;;											  \
+	cmp.eq pKern,p7=r0,r16;			/* are we in kernel mode already? (psr.cpl==0) */ \
+	/* switch from user to kernel RBS: */							  \
+	COVER;											  \
+	;; 									                  \
+	MINSTATE_START_SAVE_MIN									  \
+(p7)	mov ar.rsc=r0;		/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	  \
+(p7)	addl rKRBS=IA64_RBS_OFFSET,r1;		/* compute base of register backing store */	  \
+	;;											  \
+(p7)	mov rARRNAT=ar.rnat;									  \
+(pKern)	dep r1=0,sp,61,3;				/* compute physical addr of sp  */	  \
+(p7)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1;	/* compute base of memory stack */	  \
+(p7)	mov rARBSPSTORE=ar.bspstore;			/* save ar.bspstore */			  \
+(p7)	dep rKRBS=-1,rKRBS,61,3;			/* compute kernel virtual addr of RBS */  \
+	;;											  \
+(pKern)	addl r1=-IA64_PT_REGS_SIZE,r1;		/* if in kernel mode, use sp (r12) */		  \
+(p7)	mov ar.bspstore=rKRBS;			/* switch to kernel RBS */			  \
+	;;											  \
+(p7)	mov r18=ar.bsp;										  \
+(p7)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */		  \
+												  \
+	mov r16=r1;		/* initialize first base pointer */				  \
+	adds r17=8,r1;		/* initialize second base pointer */				  \
+	;;											  \
+	st8 [r16]=rCRIPSR,16;	/* save cr.ipsr */						  \
+	st8 [r17]=rCRIIP,16;	/* save cr.iip */						  \
+(pKern)	mov r18=r0;		/* make sure r18 isn't NaT */					  \
+	;;											  \
+	st8 [r16]=rCRIFS,16;	/* save cr.ifs */						  \
+	st8 [r17]=rARUNAT,16;	/* save ar.unat */						  \
+(p7)	sub r18=r18,rKRBS;	/* r18=RSE.ndirty*8 */						  \
+	;;											  \
+	st8 [r16]=rARPFS,16;	/* save ar.pfs */						  \
+	st8 [r17]=rARRSC,16;	/* save ar.rsc */						  \
+	tbit.nz p15,p0=rCRIPSR,IA64_PSR_I_BIT							  \
+	;;			/* avoid RAW on r16 & r17 */					  \
+(pKern)	adds r16=16,r16;	/* skip over ar_rnat field */					  \
+(pKern)	adds r17=16,r17;	/* skip over ar_bspstore field */				  \
+(p7)	st8 [r16]=rARRNAT,16;	/* save ar.rnat */						  \
+(p7)	st8 [r17]=rARBSPSTORE,16;	/* save ar.bspstore */					  \
+	;;											  \
+	st8 [r16]=rARPR,16;	/* save predicates */						  \
+	st8 [r17]=rB6,16;	/* save b6 */							  \
+	shl r18=r18,16;		/* compute ar.rsc to be used for "loadrs" */			  \
+	;;											  \
+	st8 [r16]=r18,16;	/* save ar.rsc value for "loadrs" */				  \
+	st8.spill [r17]=rR1,16;	/* save original r1 */						  \
+	cmp.ne pEOI,p0=r0,r0	/* clear pEOI by default */					  \
+	;;											  \
+.mem.offset 0,0;	st8.spill [r16]=r2,16;							  \
+.mem.offset 8,0;	st8.spill [r17]=r3,16;							  \
+	adds r2=IA64_PT_REGS_R16_OFFSET,r1;							  \
+	;;											  \
+.mem.offset 0,0;		st8.spill [r16]=r12,16;						  \
+.mem.offset 8,0;		st8.spill [r17]=r13,16;						  \
+	cmp.eq pNonSys,pSys=r0,r0	/* initialize pSys=0, pNonSys=1 */			  \
+	;;											  \
+.mem.offset 0,0;		st8.spill [r16]=r14,16;						  \
+.mem.offset 8,0;		st8.spill [r17]=r15,16;						  \
+	dep r14=-1,r0,61,3;									  \
+	;;											  \
+.mem.offset 0,0;		st8.spill [r16]=r8,16;						  \
+.mem.offset 8,0;		st8.spill [r17]=r9,16;						  \
+	adds r12=-16,r1;	/* switch to kernel memory stack (with 16 bytes of scratch) */	  \
+	;;											  \
+.mem.offset 0,0;		st8.spill [r16]=r10,16;						  \
+.mem.offset 8,0;		st8.spill [r17]=r11,16;						  \
+	mov r13=ar.k6;		/* establish `current' */					  \
+	;;											  \
+	EXTRA;											  \
+	movl r1=__gp;		/* establish kernel global pointer */				  \
+	;;											  \
+	MINSTATE_END_SAVE_MIN
+
+/*
+ * SAVE_REST saves the remainder of pt_regs (with psr.ic on).  This
+ * macro guarantees to preserve all predicate registers, r8, r9, r10,
+ * r11, r14, and r15.
+ *
+ * Assumed state upon entry:
+ *	psr.ic: on
+ *	psr.dt: on
+ *	r2:	points to &pt_regs.r16
+ *	r3:	points to &pt_regs.r17
+ */
+#define SAVE_REST				\
+.mem.offset 0,0;	st8.spill [r2]=r16,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r17,16;	\
+	;;					\
+.mem.offset 0,0;	st8.spill [r2]=r18,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r19,16;	\
+	;;					\
+	mov r16=ar.ccv;		/* M-unit */	\
+	movl r18=FPSR_DEFAULT	/* L-unit */	\
+	;;					\
+	mov r17=ar.fpsr;	/* M-unit */	\
+	mov ar.fpsr=r18;	/* M-unit */	\
+	;;					\
+.mem.offset 0,0;	st8.spill [r2]=r20,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r21,16;	\
+	mov r18=b0;				\
+	;;					\
+.mem.offset 0,0;	st8.spill [r2]=r22,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r23,16;	\
+	mov r19=b7;				\
+	;;					\
+.mem.offset 0,0;	st8.spill [r2]=r24,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r25,16;	\
+	;;					\
+.mem.offset 0,0;	st8.spill [r2]=r26,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r27,16;	\
+	;;					\
+.mem.offset 0,0;	st8.spill [r2]=r28,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r29,16;	\
+	;;					\
+.mem.offset 0,0;	st8.spill [r2]=r30,16;	\
+.mem.offset 8,0;	st8.spill [r3]=r31,16;	\
+	;;					\
+	st8 [r2]=r16,16;	/* ar.ccv */	\
+	st8 [r3]=r17,16;	/* ar.fpsr */	\
+	;;					\
+	st8 [r2]=r18,16;	/* b0 */	\
+	st8 [r3]=r19,16+8;	/* b7 */	\
+	;;					\
+	stf.spill [r2]=f6,32;			\
+	stf.spill [r3]=f7,32;			\
+	;;					\
+	stf.spill [r2]=f8,32;			\
+	stf.spill [r3]=f9,32
+
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+# define STOPS	nop.i 0x0;; nop.i 0x0;; nop.i 0x0;;
+#else
+# define STOPS
+#endif
+
+#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS
+#define SAVE_MIN_WITH_COVER_R19	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS
+#define SAVE_MIN		DO_SAVE_MIN(mov rCRIFS=r0,) STOPS
+
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+# define STOPS	nop.i 0x0;; nop.i 0x0;; nop.i 0x0;;
+#else
+# define STOPS
+#endif
+
+#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS
+#define SAVE_MIN_WITH_COVER_R19	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS
+#define SAVE_MIN		DO_SAVE_MIN(mov rCRIFS=r0,) STOPS
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/ptrace.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/ptrace.c	Fri Apr 21 15:21:24 2000
@@ -23,6 +23,16 @@
 #include <asm/uaccess.h>
 
 /*
+ * Bits in the PSR that we allow ptrace() to change:
+ *	be, up, ac, mfl, mfh (the user mask; five bits total)
+ *	db (debug breakpoint fault; one bit)
+ *	id (instruction debug fault disable; one bit)
+ *	dd (data debug fault disable; one bit)
+ *	ri (restart instruction; two bits)
+ */
+#define CR_IPSR_CHANGE_MASK 0x06a00100003eUL
+
+/*
  * Collect the NaT bits for r1-r31 from sw->caller_unat and
  * sw->ar_unat and return a NaT bitset where bit i is set iff the NaT
  * bit of register i is set.
@@ -352,6 +362,94 @@
 }
 
 /*
+ * Synchronize (i.e, write) the RSE backing store living in kernel
+ * space to the VM of the indicated child process.
+ *
+ * If new_bsp is non-zero, the bsp will (effectively) be updated to
+ * the new value upon resumption of the child process.  This is
+ * accomplished by setting the loadrs value to zero and the bspstore
+ * value to the new bsp value.
+ *
+ * When new_bsp and force_loadrs_to_zero are both 0, the register
+ * backing store in kernel space is written to user space and the
+ * loadrs and bspstore values are left alone.
+ *
+ * When new_bsp is zero and force_loadrs_to_zero is 1 (non-zero),
+ * loadrs is set to 0, and the bspstore value is set to the old bsp
+ * value.  This will cause the stacked registers (r32 and up) to be
+ * obtained entirely from the the child's memory space rather than
+ * from the kernel.  (This makes it easier to write code for
+ * modifying the stacked registers in multi-threaded programs.)
+ *
+ * Note:  I had originally written this function without the
+ * force_loadrs_to_zero parameter; it was written so that loadrs would
+ * always be set to zero.  But I had problems with certain system
+ * calls apparently causing a portion of the RBS to be zeroed.  (I
+ * still don't understand why this was happening.) Anyway, it'd
+ * definitely less intrusive to leave loadrs and bspstore alone if
+ * possible.
+ */
+static long
+sync_kernel_register_backing_store (struct task_struct *child,
+                                    long new_bsp,
+                                    int force_loadrs_to_zero)
+{
+	unsigned long *krbs, bspstore, bsp, krbs_num_regs, rbs_end, addr, val;
+	long ndirty, ret;
+	struct pt_regs *child_regs;
+	struct switch_stack *child_stack;
+
+	ret = 0;
+	child_regs = ia64_task_regs(child);
+	child_stack = (struct switch_stack *) child_regs - 1;
+
+	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
+	ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19));
+	bspstore = child_regs->ar_bspstore;
+	bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty);
+	krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore);
+	rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, krbs_num_regs);
+
+	/* Return early if nothing to do */
+	if (bsp == new_bsp)
+		return 0;
+
+	/* Write portion of backing store living on kernel stack to the child's VM. */
+	for (addr = bspstore; addr < rbs_end; addr += 8) {
+		ret = ia64_peek(child_regs, child, addr, &val);
+		if (ret != 0)
+			return ret;
+		if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val))
+			return -EIO;
+	}
+
+	if (new_bsp != 0) {
+		force_loadrs_to_zero = 1;
+		bsp = new_bsp;
+	}
+
+	if (force_loadrs_to_zero) {
+		child_regs->loadrs = 0;
+		child_regs->ar_bspstore = bsp;
+	}
+
+	return ret;
+}
+
+static void
+sync_thread_rbs (struct task_struct *child, int make_writable)
+{
+	struct task_struct *p;
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (p->mm == child->mm && p->state != TASK_RUNNING)
+			sync_kernel_register_backing_store(p, 0, make_writable);
+	}
+	read_unlock(&tasklist_lock);
+	child->thread.flags |= IA64_THREAD_KRBS_SYNCED;
+}
+
+/*
  * Ensure the state in child->thread.fph is up-to-date.
  */
 static void
@@ -375,8 +473,8 @@
 	struct switch_stack *child_stack;
 	struct pt_regs *child_regs;
 	struct task_struct *child;
-	unsigned long flags, *base;
-	long ret, regnum;
+	unsigned long flags, regnum, *base;
+	long ret;
 
 	lock_kernel();
 	ret = -EPERM;
@@ -441,6 +539,9 @@
 	switch (request) {
 	      case PTRACE_PEEKTEXT:
 	      case PTRACE_PEEKDATA:		/* read word at location addr */
+	        if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)
+		    && atomic_read(&child->mm->mm_users) > 1)
+			sync_thread_rbs(child, 0);
 		ret = ia64_peek(regs, child, addr, &data);
 		if (ret == 0) {
 			ret = data;
@@ -450,6 +551,9 @@
 
 	      case PTRACE_POKETEXT:
 	      case PTRACE_POKEDATA:		/* write the word at location addr */
+	        if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)
+		    && atomic_read(&child->mm->mm_users) > 1)
+			sync_thread_rbs(child, 1);
 		ret = ia64_poke(regs, child, addr, data);
 		goto out;
 
@@ -477,8 +581,35 @@
 				bspstore = (unsigned long *) child_regs->ar_bspstore;
 				ndirty = ia64_rse_num_regs(rbs, rbs + (ret >> 19));
 				ret = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty);
+
+				/*
+				 * If we're in a system call, no ``cover'' was done.  So
+				 * to make things uniform, we'll add the appropriate
+				 * displacement onto bsp if we're in a system call.
+				 *
+				 * Note: It may be better to leave the system call case
+				 * alone and subtract the amount of the cover for the
+				 * non-syscall case.  That way the reported bsp value
+				 * would actually be the correct bsp for the child
+				 * process.
+				 */
+				if (!(child_regs->cr_ifs & (1UL << 63))) {
+					ret = (unsigned long)
+						ia64_rse_skip_regs((unsigned long *) ret,
+						                   child_stack->ar_pfs & 0x7f);
+				}
+			} else if (addr == PT_CFM) {
+				/* ret currently contains pt_regs.cr_ifs */
+				if ((ret & (1UL << 63)) == 0)
+					ret = child_stack->ar_pfs;
+				ret &= 0x3fffffffffUL;		/* return only the CFM */
 			}
 		} else {
+			if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
+				child->thread.flags |= IA64_THREAD_DBG_VALID;
+				memset(child->thread.dbr, 0, sizeof child->thread.dbr);
+				memset(child->thread.ibr, 0, sizeof child->thread.ibr);
+			}
 			if (addr >= PT_IBR) {
 				regnum = (addr - PT_IBR) >> 3;
 				base = &child->thread.ibr[0];
@@ -488,7 +619,7 @@
 			}
 			if (regnum >= 8)
 				goto out;
-			data = base[regnum];
+			ret = base[regnum];
 		}
 		regs->r8 = 0;	/* ensure "ret" is not mistaken as an error code */
 		goto out;
@@ -503,29 +634,47 @@
 			sync_fph(child);
 			addr += (unsigned long) &child->thread.fph;
 			*(unsigned long *) addr = data;
-			if (ret < 0)
-				goto out;
+		} else if (addr == PT_AR_BSPSTORE || addr == PT_CALLER_UNAT 
+			|| addr == PT_KERNEL_FPSR || addr == PT_K_B0 || addr == PT_K_AR_PFS 
+			|| (PT_K_AR_UNAT <= addr && addr <= PT_K_PR)) {
+			/*
+			 * Don't permit changes to certain registers.
+			 * 
+			 * We don't allow bspstore to be modified because doing
+			 * so would mess up any modifications to bsp.  (See
+			 * sync_kernel_register_backing_store for the details.)
+			 */
+			goto out;
+		} else if (addr == PT_AR_BSP) {
+			/* FIXME? Account for lack of ``cover'' in the syscall case */
+			ret = sync_kernel_register_backing_store(child, data, 1);
+			goto out;
+		} else if (addr == PT_CFM) {
+			child_regs = ia64_task_regs(child);
+			child_stack = (struct switch_stack *) child_regs - 1;
+
+			if (child_regs->cr_ifs & (1UL << 63)) {
+				child_regs->cr_ifs = (child_regs->cr_ifs & ~0x3fffffffffUL)
+				                   | (data & 0x3fffffffffUL);
+			} else {
+				child_stack->ar_pfs = (child_stack->ar_pfs & ~0x3fffffffffUL)
+				                    | (data & 0x3fffffffffUL);
+			}
 		} else if (addr < PT_F9+16) {
 			/* accessing switch_stack or pt_regs */
 			child_regs = ia64_task_regs(child);
 			child_stack = (struct switch_stack *) child_regs - 1;
 
-			if (addr == PT_AR_BSP) {
-				/* compute the loadrs value based on bsp and bspstore: */
-				unsigned long *rbs, *bspstore, ndirty, *kbsp;
-
-				bspstore = (unsigned long *) child_regs->ar_bspstore;
-				ndirty = ia64_rse_num_regs(bspstore, (unsigned long *) data);
-				rbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-				kbsp = ia64_rse_skip_regs(rbs, ndirty);
-				data = (kbsp - rbs) << 19;
-			}
+			if (addr == PT_CR_IPSR)
+				data = (data & CR_IPSR_CHANGE_MASK)
+				     | (child_regs->cr_ipsr & ~CR_IPSR_CHANGE_MASK);
+			
 			*(unsigned long *) ((long) child_stack + addr - PT_CALLER_UNAT) = data;
 		} else {
 			if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
 				child->thread.flags |= IA64_THREAD_DBG_VALID;
-				memset(current->thread.dbr, 0, sizeof current->thread.dbr);
-				memset(current->thread.ibr, 0, sizeof current->thread.ibr);
+				memset(child->thread.dbr, 0, sizeof child->thread.dbr);
+				memset(child->thread.ibr, 0, sizeof child->thread.ibr);
 			}
 
 			if (addr >= PT_IBR) {
@@ -538,7 +687,7 @@
 			if (regnum >= 8)
 				goto out;
 			if (regnum & 1) {
-				/* force breakpoint to be effective a most for user-level: */
+				/* force breakpoint to be effective only for user-level: */
 				data &= ~(0x7UL << 56);
 			}
 			base[regnum] = data;
@@ -546,6 +695,23 @@
 		ret = 0;
 		goto out;
 
+	      case PTRACE_GETSIGINFO:
+		ret = -EIO;
+		if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t))
+		    || child->thread.siginfo == 0)
+			goto out;
+		copy_to_user((siginfo_t *) data, child->thread.siginfo, sizeof (siginfo_t));
+		ret = 0;
+		goto out;
+		break;
+	      case PTRACE_SETSIGINFO:
+		ret = -EIO;
+		if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t))
+		    || child->thread.siginfo == 0)
+			goto out;
+		copy_from_user(child->thread.siginfo, (siginfo_t *) data, sizeof (siginfo_t));
+		ret = 0;
+		goto out;
 	      case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
 	      case PTRACE_CONT:		/* restart after signal. */
 		ret = -EIO;
@@ -561,6 +727,9 @@
 		ia64_psr(ia64_task_regs(child))->ss = 0;
 		ia64_psr(ia64_task_regs(child))->tb = 0;
 
+		/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
+		child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
+
 		wake_up_process(child);
 		ret = 0;
 		goto out;
@@ -579,6 +748,9 @@
 		ia64_psr(ia64_task_regs(child))->ss = 0;
 		ia64_psr(ia64_task_regs(child))->tb = 0;
 
+		/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
+		child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
+
 		wake_up_process(child);
 		ret = 0;
 		goto out;
@@ -597,6 +769,9 @@
 		}
 		child->exit_code = data;
 
+		/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
+		child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
+
 		/* give it a chance to run. */
 		wake_up_process(child);
 		ret = 0;
@@ -618,6 +793,9 @@
 		/* make sure the single step/take-branch tra bits are not set: */
 		ia64_psr(ia64_task_regs(child))->ss = 0;
 		ia64_psr(ia64_task_regs(child))->tb = 0;
+
+		/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
+		child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
 
 		wake_up_process(child);
 		ret = 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/sal.c linux/arch/ia64/kernel/sal.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/sal.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/sal.c	Fri Apr 21 15:21:24 2000
@@ -139,7 +139,7 @@
 				    case IA64_SAL_AP_EXTERNAL_INT:
 				      ap_wakeup_vector = ap->vector;
 # ifdef SAL_DEBUG
-				      printk("SAL: AP wakeup using external interrupt; "
+				      printk("SAL: AP wakeup using external interrupt "
 					     "vector 0x%lx\n", ap_wakeup_vector);
 # endif
 				      break;
@@ -151,6 +151,36 @@
 			      break;
 		      }
 #endif
+		      case SAL_DESC_PLATFORM_FEATURE:
+		      {
+			      struct ia64_sal_desc_platform_feature *pf = (void *) p;
+			      printk("SAL: Platform features ");
+
+			      if (pf->feature_mask & (1 << 0))
+				      printk("BusLock ");
+
+			      if (pf->feature_mask & (1 << 1)) {
+				      printk("IRQ_Redirection ");
+#ifdef CONFIG_SMP
+				      if (no_int_routing) 
+					      smp_int_redirect &= ~SMP_IRQ_REDIRECTION;
+				      else
+					      smp_int_redirect |= SMP_IRQ_REDIRECTION;
+#endif
+			      }
+			      if (pf->feature_mask & (1 << 2)) {
+				      printk("IPI_Redirection ");
+#ifdef CONFIG_SMP
+				      if (no_int_routing) 
+					      smp_int_redirect &= ~SMP_IPI_REDIRECTION;
+				      else
+					      smp_int_redirect |= SMP_IPI_REDIRECTION;
+#endif
+			      }
+			      printk("\n");
+			      break;
+ 		      }
+
 		}
 		p += SAL_DESC_SIZE(*p);
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/sal_stub.S linux/arch/ia64/kernel/sal_stub.S
--- v2.3.99-pre5/linux/arch/ia64/kernel/sal_stub.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/sal_stub.S	Fri Apr 21 15:21:24 2000
@@ -1,17 +1,19 @@
 /*
- * gcc currently does not conform to the ia-64 calling convention as far
- * as returning function values are concerned.  Instead of returning
- * values up to 32 bytes in size in r8-r11, gcc returns any value
- * bigger than a doubleword via a structure that's allocated by the
- * caller and whose address is passed into the function.  Since
- * SAL_PROC returns values according to the calling convention, this
- * stub takes care of copying r8-r11 to the place where gcc expects
- * them.
- *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #ifndef __GCC_MULTIREG_RETVALS__
+	/*
+	 * gcc currently does not conform to the ia-64 calling
+	 * convention as far as returning function values are
+	 * concerned.  Instead of returning values up to 32 bytes in
+	 * size in r8-r11, gcc returns any value bigger than a
+	 * doubleword via a structure that's allocated by the caller
+	 * and whose address is passed into the function.  Since
+	 * SAL_PROC returns values according to the calling
+	 * convention, this stub takes care of copying r8-r11 to the
+	 * place where gcc expects them.
+	 */
 	.text
 	.psr abi64
 	.psr lsb
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/semaphore.c linux/arch/ia64/kernel/semaphore.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/semaphore.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/semaphore.c	Fri Apr 21 15:21:24 2000
@@ -310,7 +310,7 @@
 		do {
 			old_count = sem->count;
 			count = old_count - RW_LOCK_BIAS;
-		} while (cmpxchg(&sem->count, old_count, count) != old_count);
+		} while (cmpxchg_acq(&sem->count, old_count, count) != old_count);
 
 		if (count == 0)
 			return;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/setup.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/setup.c	Fri Apr 21 15:21:24 2000
@@ -8,10 +8,12 @@
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  *
- * 02/04/00 D.Mosberger some more get_cpuinfo fixes...
- * 02/01/00 R.Seth fixed get_cpuinfo for SMP
- * 01/07/99 S.Eranian added the support for command line argument
- * 06/24/99 W.Drummond added boot_cpu_data.
+ * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map
+ * 03/31/00 R.Seth	cpu_initialized and current->processor fixes
+ * 02/04/00 D.Mosberger	some more get_cpuinfo fixes...
+ * 02/01/00 R.Seth	fixed get_cpuinfo for SMP
+ * 01/07/99 S.Eranian	added the support for command line argument
+ * 06/24/99 W.Drummond	added boot_cpu_data.
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -32,6 +34,7 @@
 #include <asm/sal.h>
 #include <asm/system.h>
 #include <asm/efi.h>
+#include <asm/mca.h>
 
 extern char _end;
 
@@ -41,10 +44,13 @@
 unsigned long ia64_cycles_per_usec;
 struct ia64_boot_param ia64_boot_param;
 struct screen_info screen_info;
-unsigned long cpu_initialized = 0;
 /* This tells _start which CPU is booting.  */
 int cpu_now_booting = 0;
 
+#ifdef CONFIG_SMP
+volatile unsigned long cpu_online_map;
+#endif
+
 #define COMMAND_LINE_SIZE	512
 
 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */
@@ -101,7 +107,6 @@
 setup_arch (char **cmdline_p)
 {
 	unsigned long max_pfn, bootmap_start, bootmap_size;
-	u64 progress;
 
 	/*
 	 * The secondary bootstrap loader passes us the boot
@@ -147,7 +152,10 @@
 
 	printk("args to kernel: %s\n", *cmdline_p);
 
-#ifndef CONFIG_SMP
+#ifdef CONFIG_SMP
+	bootstrap_processor = hard_smp_processor_id();
+	current->processor = bootstrap_processor;
+#else
 	cpu_init();
 	identify_cpu(&cpu_data[0]);
 #endif
@@ -168,6 +176,11 @@
 	conswitchp = &dummy_con;
 # endif
 #endif
+
+#ifdef CONFIG_IA64_MCA
+	/* enable IA-64 Machine Check Abort Handling */
+	ia64_mca_init();
+#endif
 	paging_init();
 	platform_setup(cmdline_p);
 }
@@ -183,8 +196,10 @@
 	unsigned long mask;
 
 	for (c = cpu_data; c < cpu_data + NR_CPUS; ++c) {
-		if (!(cpu_initialized & (1UL << (c - cpu_data))))
+#ifdef CONFIG_SMP
+		if (!(cpu_online_map & (1UL << (c - cpu_data))))
 			continue;
+#endif
 
 		mask = c->features;
 
@@ -209,7 +224,7 @@
 		if (mask)
 			sprintf(cp, " 0x%lx", mask);
 
-		p += sprintf(buffer,
+		p += sprintf(p,
 			     "CPU# %lu\n"
 			     "\tvendor     : %s\n"
 			     "\tfamily     : %s\n"
@@ -303,8 +318,6 @@
 void
 cpu_init (void)
 {
-	int nr = smp_processor_id();
-
 	/* Clear the stack memory reserved for pt_regs: */
 	memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
 
@@ -318,11 +331,6 @@
 	 */
 	ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP);
 	ia64_set_fpu_owner(0);		/* initialize ar.k5 */
-
-	if (test_and_set_bit(nr, &cpu_initialized)) {
-		printk("CPU#%d already initialized!\n", nr);
-		machine_halt();
-	}
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/signal.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/signal.c	Fri Apr 21 15:21:24 2000
@@ -94,7 +94,7 @@
 restore_sigcontext (struct sigcontext *sc, struct pt_regs *pt)
 {
 	struct switch_stack *sw = (struct switch_stack *) pt - 1;
-	unsigned long ip, flags, nat, um;
+	unsigned long ip, flags, nat, um, cfm;
 	long err;
 
 	/* restore scratch that always needs gets updated during signal delivery: */
@@ -102,20 +102,24 @@
 
 	err |= __get_user(nat, &sc->sc_nat);
 	err |= __get_user(ip, &sc->sc_ip);			/* instruction pointer */
-	err |= __get_user(pt->ar_fpsr, &sc->sc_ar_fpsr);
-	err |= __get_user(pt->ar_pfs, &sc->sc_ar_pfs);
+	err |= __get_user(cfm, &sc->sc_cfm);
 	err |= __get_user(um, &sc->sc_um);			/* user mask */
 	err |= __get_user(pt->ar_rsc, &sc->sc_ar_rsc);
 	err |= __get_user(pt->ar_ccv, &sc->sc_ar_ccv);
 	err |= __get_user(pt->ar_unat, &sc->sc_ar_unat);
+	err |= __get_user(pt->ar_fpsr, &sc->sc_ar_fpsr);
+	err |= __get_user(pt->ar_pfs, &sc->sc_ar_pfs);
 	err |= __get_user(pt->pr, &sc->sc_pr);			/* predicates */
 	err |= __get_user(pt->b0, &sc->sc_br[0]);		/* b0 (rp) */
-	err |= __get_user(pt->b6, &sc->sc_br[6]);
+	err |= __get_user(pt->b6, &sc->sc_br[6]);		/* b6 */
+	err |= __get_user(pt->b7, &sc->sc_br[7]);		/* b7 */
 	err |= __copy_from_user(&pt->r1, &sc->sc_gr[1], 3*8);	/* r1-r3 */
 	err |= __copy_from_user(&pt->r8, &sc->sc_gr[8], 4*8);	/* r8-r11 */
 	err |= __copy_from_user(&pt->r12, &sc->sc_gr[12], 4*8);	/* r12-r15 */
 	err |= __copy_from_user(&pt->r16, &sc->sc_gr[16], 16*8);	/* r16-r31 */
 
+	pt->cr_ifs = cfm | (1UL << 63);
+
 	/* establish new instruction pointer: */
 	pt->cr_iip = ip & ~0x3UL;
 	ia64_psr(pt)->ri = ip & 0x3;
@@ -240,6 +244,7 @@
 	nat = ia64_get_nat_bits(pt, sw);
 
 	err  = __put_user(flags, &sc->sc_flags);
+
 	err |= __put_user(nat, &sc->sc_nat);
 	err |= PUT_SIGSET(mask, &sc->sc_mask);
 	err |= __put_user(pt->cr_ipsr & IA64_PSR_UM, &sc->sc_um);
@@ -255,8 +260,8 @@
 
 	err |= __copy_to_user(&sc->sc_gr[1], &pt->r1, 3*8);		/* r1-r3 */
 	err |= __copy_to_user(&sc->sc_gr[8], &pt->r8, 4*8);		/* r8-r11 */
-	err |= __copy_to_user(&sc->sc_gr[12], &pt->r12, 4*8);	/* r12-r15 */
-	err |= __copy_to_user(&sc->sc_gr[16], &pt->r16, 16*8);	/* r16-r31 */
+	err |= __copy_to_user(&sc->sc_gr[12], &pt->r12, 4*8);		/* r12-r15 */
+	err |= __copy_to_user(&sc->sc_gr[16], &pt->r16, 16*8);		/* r16-r31 */
 
 	err |= __put_user(pt->cr_iip + ia64_psr(pt)->ri, &sc->sc_ip);
 	err |= __put_user(pt->r12, &sc->sc_gr[12]);			/* r12 */
@@ -415,10 +420,12 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			/* Let the debugger run.  */
 			current->exit_code = signr;
+			current->thread.siginfo = &info;
 			set_current_state(TASK_STOPPED);
 			notify_parent(current, SIGCHLD);
 			schedule();
 			signr = current->exit_code;
+			current->thread.siginfo = 0;
 
 			/* We're back.  Did the debugger cancel the sig?  */
 			if (!signr)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/smp.c	Sun Feb 13 19:29:03 2000
+++ linux/arch/ia64/kernel/smp.c	Fri Apr 21 15:21:24 2000
@@ -6,6 +6,8 @@
  * 
  * Lots of stuff stolen from arch/alpha/kernel/smp.c
  *
+ *  00/03/31 Rohit Seth <rohit.seth@intel.com>	Fixes for Bootstrap Processor & cpu_online_map
+ *			now gets done here (instead of setup.c)
  *  99/10/05 davidm	Update to bring it in sync with new command-line processing scheme.
  */
 #define __KERNEL_SYSCALLS__
@@ -24,15 +26,6 @@
 #include <asm/bitops.h>
 #include <asm/current.h>
 #include <asm/delay.h>
-
-#ifdef CONFIG_KDB
-#include <linux/kdb.h>
-void smp_kdb_interrupt (struct pt_regs* regs);
-void kdb_global(int cpuid);
-extern unsigned long smp_kdb_wait;
-extern int kdb_new_cpu;
-#endif
-
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/page.h>
@@ -47,25 +40,24 @@
 extern int cpu_idle(void * unused);
 extern void _start(void);
 
-extern int cpu_now_booting;                          /* Used by head.S to find idle task */
-extern unsigned long cpu_initialized;                /* Bitmap of available cpu's */
-extern struct cpuinfo_ia64 cpu_data[NR_CPUS];        /* Duh... */
+extern int cpu_now_booting;			     /* Used by head.S to find idle task */
+extern volatile unsigned long cpu_online_map;	     /* Bitmap of available cpu's */
+extern struct cpuinfo_ia64 cpu_data[NR_CPUS];	     /* Duh... */
 
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
-#ifdef CONFIG_KDB
-unsigned long cpu_online_map = 1;
-#endif
+struct smp_boot_data __initdata smp;
+char __initdata no_int_routing = 0;
 
+unsigned char smp_int_redirect;			/* are INT and IPI redirectable by the chipset? */
 volatile int __cpu_number_map[NR_CPUS] = { -1, };    /* SAPIC ID -> Logical ID */
 volatile int __cpu_logical_map[NR_CPUS] = { -1, };   /* logical ID -> SAPIC ID */
 int smp_num_cpus = 1;		
-int bootstrap_processor = -1;                        /* SAPIC ID of BSP */
-int smp_threads_ready = 0;	                     /* Set when the idlers are all forked */
-unsigned long ipi_base_addr = IPI_DEFAULT_BASE_ADDR; /* Base addr of IPI table */
+int bootstrap_processor = -1;			     /* SAPIC ID of BSP */
+int smp_threads_ready = 0;			     /* Set when the idlers are all forked */
 cycles_t cacheflush_time = 0;
-unsigned long ap_wakeup_vector = -1;                 /* External Int to use to wakeup AP's */
-static int max_cpus = -1;	                     /* Command line */
+unsigned long ap_wakeup_vector = -1;		     /* External Int to use to wakeup AP's */
+static int max_cpus = -1;			     /* Command line */
 static unsigned long ipi_op[NR_CPUS];
 struct smp_call_struct {
 	void (*func) (void *info);
@@ -76,20 +68,13 @@
 };
 static struct smp_call_struct *smp_call_function_data;
 
-#ifdef CONFIG_KDB
-unsigned long smp_kdb_wait = 0;                         /* Bitmask of waiters */
-#endif
-
 #ifdef	CONFIG_ITANIUM_ASTEP_SPECIFIC
 extern spinlock_t ivr_read_lock;
 #endif
 
-int use_xtp = 0;		/* XXX */
-
 #define IPI_RESCHEDULE	        0
 #define IPI_CALL_FUNC	        1
 #define IPI_CPU_STOP	        2
-#define IPI_KDB_INTERRUPT	4
 
 /*
  *	Setup routine for controlling SMP activation
@@ -118,13 +103,22 @@
 
 __setup("maxcpus=", maxcpus);
 
+static int __init
+nointroute(char *str)
+{
+	no_int_routing = 1;
+	return 1;
+}
+
+__setup("nointroute", nointroute);
+
 /*
  * Yoink this CPU from the runnable list... 
  */
 void
 halt_processor(void) 
 {
-        clear_bit(smp_processor_id(), &cpu_initialized);
+        clear_bit(smp_processor_id(), &cpu_online_map);
 	max_xtp();
 	__cli();
         for (;;)
@@ -188,12 +182,6 @@
 			halt_processor();
 			break;
 
-#ifdef CONFIG_KDB
-		case IPI_KDB_INTERRUPT:
-			smp_kdb_interrupt(regs);
-			break;
-#endif
-
 		default:
 			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
 			break;
@@ -205,32 +193,6 @@
 }
 
 static inline void
-send_IPI(int dest_cpu, unsigned char vector)
-{
-	unsigned long ipi_addr;
-	unsigned long ipi_data;
-#ifdef	CONFIG_ITANIUM_ASTEP_SPECIFIC
-	unsigned long flags;
-#endif
-
-	ipi_data = vector;
-	ipi_addr = ipi_base_addr | ((dest_cpu << 8) << 4); /* 16-bit SAPIC ID's; assume CPU bus 0 */
-	mb();
-
-#ifdef	CONFIG_ITANIUM_ASTEP_SPECIFIC
-	/*
-	 * Disable IVR reads
-	 */
-	spin_lock_irqsave(&ivr_read_lock, flags);
-	writeq(ipi_data, ipi_addr);
-	spin_unlock_irqrestore(&ivr_read_lock, flags);
-#else
- 	writeq(ipi_data, ipi_addr);
-#endif	/* CONFIG_ITANIUM_ASTEP_SPECIFIC */
-
-}
-
-static inline void
 send_IPI_single(int dest_cpu, int op) 
 {
 	
@@ -238,7 +200,7 @@
                 return;
         
         ipi_op[dest_cpu] |= (1 << op);
-	send_IPI(dest_cpu, IPI_IRQ);
+	ipi_send(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0);
 }
 
 static inline void
@@ -452,9 +414,11 @@
 	ia64_clear_ic(flags);
 	ia64_set_rr(          0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2));
 	ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2));
+	ia64_srlz_d();
 	ia64_itr(0x3, 1, PAGE_OFFSET,
 		 pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))),
 		 _PAGE_SIZE_256M);
+	ia64_srlz_i();
 
 	flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | 
 		 IA64_PSR_BN);
@@ -492,6 +456,10 @@
 	smp_store_cpu_info(smp_processor_id());
 	smp_setup_percpu_timer(smp_processor_id());
 
+	if (test_and_set_bit(smp_processor_id(), &cpu_online_map)) {
+		printk("CPU#%d already initialized!\n", smp_processor_id());
+		machine_halt();
+	}  
 	while (!smp_threads_ready) 
 		mb();
 
@@ -505,6 +473,9 @@
 	ia64_set_lrr1(0, 1);	
 
 	__sti();		/* Interrupts have been off till now. */
+
+	printk("SMP: CPU %d starting idle loop\n", smp_processor_id());
+
 	cpu_idle(NULL);
 }
 
@@ -565,7 +536,7 @@
 	cpu_now_booting = cpunum;
 	
 	/* Kick the AP in the butt */
-	send_IPI(cpuid, ap_wakeup_vector);
+	ipi_send(cpuid, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
 	ia64_srlz_i();
 	mb();
 
@@ -575,24 +546,20 @@
 	 * is waiting for smp_threads_ready to be 1 and we can move on.
 	 */
 	for (timeout = 0; timeout < 100000; timeout++) {
-		if (test_bit(cpuid, &cpu_initialized))
+		if (test_bit(cpuid, &cpu_online_map))
 			goto alive;
-		udelay(10);
+		udelay(100);
 		barrier();
 	}
 
 	printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
-	return -1;
+	return 0;
 
 alive:
 	/* Remember the AP data */
 	__cpu_number_map[cpuid] = cpunum;
-#ifdef CONFIG_KDB
-        cpu_online_map |= (1<<cpunum);
-        printk ("DEBUGGER: cpu_online_map = 0x%08x\n", cpu_online_map);
-#endif
 	__cpu_logical_map[cpunum] = cpuid;
-	return 0;
+	return 1;
 }
 
 
@@ -607,9 +574,6 @@
 {
 	int i, cpu_count = 1;
 	unsigned long bogosum;
-	int sapic_id;
-	extern int acpi_cpus;
-	extern int acpi_apic_map[32];
 
 	/* Take care of some initial bookkeeping.  */
 	memset(&__cpu_number_map, -1, sizeof(__cpu_number_map));
@@ -634,6 +598,10 @@
 #endif
  	smp_setup_percpu_timer(bootstrap_processor);
 
+	if (test_and_set_bit(bootstrap_processor, &cpu_online_map)) {
+		printk("CPU#%d already initialized!\n", smp_processor_id());
+		machine_halt();
+	}  
 	init_idle();
 
 	/* Nothing to do when told not to.  */
@@ -642,33 +610,36 @@
 		return;
 	}
 
-	if (acpi_cpus > 1) {
+	if (max_cpus != -1) 
+		printk("Limiting CPUs to %d\n", max_cpus);
+
+	if (smp.cpu_count > 1) {
 		printk(KERN_INFO "SMP: starting up secondaries.\n");
 
 		for (i = 0; i < NR_CPUS; i++) {
-			if (acpi_apic_map[i] == -1 || 
-			    acpi_apic_map[i] == bootstrap_processor << 8) /* XXX Fix me Walt */
+			if (smp.cpu_map[i] == -1 || 
+			    smp.cpu_map[i] == bootstrap_processor)
 				continue;
 
-			/*
-			 * IA64 SAPIC ID's are 16-bits.  See asm/smp.h for more info 
-			 */
-			sapic_id = acpi_apic_map[i] >> 8;
-			if (smp_boot_one_cpu(sapic_id, cpu_count))
+			if (smp_boot_one_cpu(smp.cpu_map[i], cpu_count) == 0)
 				continue;
 
 			cpu_count++; /* Count good CPUs only... */
+			/* 
+			 * Bail if we've started as many CPUS as we've been told to.
+			 */
+			if (cpu_count == max_cpus)
+				break;
 		}
 	}
 
 	if (cpu_count == 1) {
 		printk(KERN_ERR "SMP: Bootstrap processor only.\n");
-		return;
 	}
 
 	bogosum = 0;
         for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_initialized & (1L << i))
+		if (cpu_online_map & (1L << i))
 			bogosum += cpu_data[i].loops_per_sec;
         }
 
@@ -733,45 +704,8 @@
 	if (sal_ret < 0) {
 		printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret));
 		printk("     Forcing UP mode\n");
+		max_cpus = 0;
 		smp_num_cpus = 1; 
 	}
 
 }
-
-#ifdef CONFIG_KDB
-void smp_kdb_stop (int all, struct pt_regs* regs)
-{
-        if (all)
-      {
-              printk ("Sending IPI to all on CPU %i\n", smp_processor_id ());
-                smp_kdb_wait = 0xffffffff;
-                clear_bit (smp_processor_id(), &smp_kdb_wait);
-                send_IPI_allbutself (IPI_KDB_INTERRUPT);
-        }
-      else
-      {
-              printk ("Sending IPI to self on CPU %i\n",
-                      smp_processor_id ());
-                set_bit (smp_processor_id(), &smp_kdb_wait);
-              clear_bit (__cpu_logical_map[kdb_new_cpu], &smp_kdb_wait);
-                smp_kdb_interrupt (regs);
-        }
-}
-
-void smp_kdb_interrupt (struct pt_regs* regs)
-{
-        printk ("kdb: IPI on CPU %i with mask 0x%08x\n",
-              smp_processor_id (), smp_kdb_wait);
-
-      /* All CPUs spin here forever */
-        while (test_bit (smp_processor_id(), &smp_kdb_wait));
-
-      /* Enter KDB on CPU selected by KDB on the last CPU */
-        if (__cpu_logical_map[kdb_new_cpu] == smp_processor_id ())
-      {
-                kdb (KDB_REASON_SWITCH, 0, regs);
-        }
-}
-
-#endif
-
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/smpboot.c linux/arch/ia64/kernel/smpboot.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/smpboot.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/kernel/smpboot.c	Fri Apr 21 15:21:24 2000
@@ -0,0 +1,2 @@
+unsigned long cpu_online_map;
+
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/time.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/time.c	Fri Apr 21 15:21:24 2000
@@ -9,11 +9,12 @@
  * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
  */
 #include <linux/config.h>
+
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/time.h>
+#include <linux/interrupt.h>
 
 #include <asm/delay.h>
 #include <asm/efi.h>
@@ -136,6 +137,7 @@
 	static unsigned long last_time;
 	static unsigned char count;
 	int cpu = smp_processor_id();
+	int printed = 0;
 
 	/*
 	 * Here we are in the timer irq handler. We have irqs locally
@@ -145,9 +147,14 @@
 	 */
 	write_lock(&xtime_lock);
 	while (1) {
-		/* do kernel PC profiling here.  */
+		/*
+		 * Do kernel PC profiling here.  We multiply the
+		 * instruction number by four so that we can use a
+		 * prof_shift of 2 to get instruction-level instead of
+		 * just bundle-level accuracy.
+		 */
 		if (!user_mode(regs)) 
-			do_profile(regs->cr_iip);
+			do_profile(regs->cr_iip + 4*ia64_psr(regs)->ri);
 
 #ifdef CONFIG_SMP
 		smp_do_timer(regs);
@@ -172,15 +179,18 @@
 
 #if !(defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_SMP))
 		/*
-		 * SoftSDV in SMP mode is _slow_, so we do "loose" ticks, 
+		 * SoftSDV in SMP mode is _slow_, so we do "lose" ticks, 
 		 * but it's really OK...
 		 */
 		if (count > 0 && jiffies - last_time > 5*HZ)
 			count = 0;
 		if (count++ == 0) {
 			last_time = jiffies;
-			printk("Lost clock tick on CPU %d (now=%lx, next=%lx)!!\n",
-			       cpu, ia64_get_itc(), itm.next[cpu]);
+			if (!printed) {
+				printk("Lost clock tick on CPU %d (now=%lx, next=%lx)!!\n",
+				       cpu, ia64_get_itc(), itm.next[cpu]);
+				printed = 1;
+			}
 # ifdef CONFIG_IA64_DEBUG_IRQ
 			printk("last_cli_ip=%lx\n", last_cli_ip);
 # endif
@@ -303,8 +313,6 @@
 time_init (void)
 {
 	/* we can't do request_irq() here because the kmalloc() would fail... */
-	irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
-	irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal;
 	setup_irq(TIMER_IRQ, &timer_irqaction);
 
 	efi_gettimeofday(&xtime);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/traps.c	Fri Mar 10 16:40:39 2000
+++ linux/arch/ia64/kernel/traps.c	Fri Apr 21 15:21:24 2000
@@ -32,10 +32,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 
-#ifdef CONFIG_KDB
-# include <linux/kdb.h>
-#endif
-
+#include <asm/ia32.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 
@@ -88,13 +85,6 @@
 
 	printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
 
-#ifdef CONFIG_KDB
-	while (1) {
-                kdb(KDB_REASON_PANIC, 0, regs);
-                printk("Cant go anywhere from Panic!\n");
-	}
-#endif
-
 	show_regs(regs);
 
 	if (current->thread.flags & IA64_KERNEL_DEATH) {
@@ -440,7 +430,18 @@
 	      case 35: /* Taken Branch Trap */
 	      case 36: /* Single Step Trap */
 		switch (vector) {
-		      case 29: siginfo.si_code = TRAP_BRKPT; break;
+		      case 29: 
+			siginfo.si_code = TRAP_HWBKPT;
+#ifdef CONFIG_ITANIUM
+			/*
+			 * Erratum 10 (IFA may contain incorrect address) now has
+			 * "NoFix" status.  There are no plans for fixing this.
+			 */
+			if (ia64_psr(regs)->is == 0)
+			  ifa = regs->cr_iip;
+#endif
+			siginfo.si_addr = (void *) ifa;
+		        break;
 		      case 35: siginfo.si_code = TRAP_BRANCH; break;
 		      case 36: siginfo.si_code = TRAP_TRACE; break;
 		}
@@ -479,12 +480,18 @@
 		break;
 
 	      case 45:
-		printk("Unexpected IA-32 exception\n");
+#ifdef CONFIG_IA32_SUPPORT
+		if (ia32_exception(regs, isr) == 0)
+			return;
+#endif
+		printk("Unexpected IA-32 exception (Trap 45)\n");
+		printk("  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", regs->cr_iip, ifa, isr);
 		force_sig(SIGSEGV, current);
-		return;
+		break;
 
 	      case 46:
-		printk("Unexpected IA-32 intercept trap\n");
+		printk("Unexpected IA-32 intercept trap (Trap 46)\n");
+		printk("  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", regs->cr_iip, ifa, isr);
 		force_sig(SIGSEGV, current);
 		return;
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c
--- v2.3.99-pre5/linux/arch/ia64/kernel/unaligned.c	Sat Feb 26 22:31:39 2000
+++ linux/arch/ia64/kernel/unaligned.c	Fri Apr 21 15:21:24 2000
@@ -305,7 +305,7 @@
 	DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n",
 		addr, rnats, nat, rnats &ia64_rse_slot_num(slot)));
 	
-	if ( nat ) {
+	if (nat) {
 		rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot);
 	} else {
 		rnats &= ~(__IA64_UL(1) << ia64_rse_slot_num(slot));
@@ -385,7 +385,8 @@
 	ia64_peek(regs, current, (unsigned long)addr, &rnats);
 	DPRINT(("rnat @%p = 0x%lx\n", addr, rnats));
 	
-	if ( nat ) *nat = rnats >> ia64_rse_slot_num(slot) & 0x1;
+	if (nat)
+		*nat = rnats >> ia64_rse_slot_num(slot) & 0x1;
 }
 
 
@@ -401,7 +402,7 @@
 	/*
 	 * First takes care of stacked registers
 	 */
- 	if ( regnum >= IA64_FIRST_STACKED_GR ) {
+ 	if (regnum >= IA64_FIRST_STACKED_GR) {
 		set_rse_reg(regs, regnum, val, nat);
 		return;
 	}
@@ -414,7 +415,7 @@
 	/*
 	 * Now look at registers in [0-31] range and init correct UNAT
 	 */
-	if ( GR_IN_SW(regnum) ) {
+	if (GR_IN_SW(regnum)) {
 		addr = (unsigned long)sw;
 		unat = &sw->ar_unat;
 	} else {
@@ -437,7 +438,7 @@
 	 */
 	bitmask   = __IA64_UL(1) << (addr >> 3 & 0x3f);
 	DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, unat, *unat));
-	if ( nat ) {
+	if (nat) {
 		*unat |= bitmask;
 	} else {
 		*unat &= ~bitmask;
@@ -465,7 +466,7 @@
 	 * fly to store to the right register.
 	 * For now, we are using the (slow) save/restore way.
 	 */
- 	if ( regnum >= IA64_FIRST_ROTATING_FR ) {
+ 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		/*
 		 * force a save of [32-127] to tss
 		 * we use the __() form to avoid fiddling with the dfh bit
@@ -489,7 +490,7 @@
 		/*
 		 * pt_regs or switch_stack ?
 		 */
-		if ( FR_IN_SW(regnum) ) {
+		if (FR_IN_SW(regnum)) {
 			addr = (unsigned long)sw;
 		} else {
 			addr = (unsigned long)regs;
@@ -542,7 +543,7 @@
 	 * we need to force a save to the tss to get access to it.
 	 * See discussion in setfpreg() for reasons and other ways of doing this.
 	 */
- 	if ( regnum >= IA64_FIRST_ROTATING_FR ) {
+ 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 	
 		/*
 		 * force a save of [32-127] to tss
@@ -587,7 +588,7 @@
 	struct switch_stack *sw = (struct switch_stack *)regs -1;
 	unsigned long addr, *unat;
 
- 	if ( regnum >= IA64_FIRST_STACKED_GR ) {
+ 	if (regnum >= IA64_FIRST_STACKED_GR) {
 		get_rse_reg(regs, regnum, val, nat);
 		return;
 	}
@@ -595,7 +596,7 @@
 	/*
 	 * take care of r0 (read-only always evaluate to 0)
 	 */
-	if ( regnum == 0 ) {
+	if (regnum == 0) {
 		*val = 0;
 		*nat = 0;
 		return;
@@ -604,7 +605,7 @@
 	/*
 	 * Now look at registers in [0-31] range and init correct UNAT
 	 */
-	if ( GR_IN_SW(regnum) ) {
+	if (GR_IN_SW(regnum)) {
 		addr = (unsigned long)sw;
 		unat = &sw->ar_unat;
 	} else {
@@ -621,7 +622,8 @@
 	/*
 	 * do it only when requested
 	 */
-	if ( nat ) *nat  = (*unat >> (addr >> 3 & 0x3f)) & 0x1UL;
+	if (nat)
+		*nat  = (*unat >> (addr >> 3 & 0x3f)) & 0x1UL;
 }
 
 static void
@@ -633,7 +635,7 @@
 	 * not get to this point in the code but we keep this sanity check,
 	 * just in case.
 	 */
-	if ( ld->x6_op == 1 || ld->x6_op == 3 ) {
+	if (ld->x6_op == 1 || ld->x6_op == 3) {
 		printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n");	
 		die_if_kernel("unaligned reference on specualtive load with register update\n",
 			      regs, 30);
@@ -644,7 +646,7 @@
 	 * at this point, we know that the base register to update is valid i.e.,
 	 * it's not r0
 	 */
-	if ( type == UPD_IMMEDIATE ) {
+	if (type == UPD_IMMEDIATE) {
 		unsigned long imm;
 
 		/* 
@@ -670,7 +672,7 @@
 
 		DPRINT(("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld->x, ld->m, imm, ifa));
 
-	} else if ( ld->m ) {
+	} else if (ld->m) {
 		unsigned long r2;
 		int nat_r2;
 
@@ -719,7 +721,7 @@
 	 *
 	 * Note: the first argument is ignored 
 	 */
-	if ( access_ok(VERIFY_READ, (void *)ifa, len) < 0 ) {
+	if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) {
 		DPRINT(("verify area failed on %lx\n", ifa));
 		return -1;
 	}
@@ -737,7 +739,7 @@
 	 * invalidate the ALAT entry.
 	 * See comment below for explanation on how we handle ldX.a
 	 */
-	if ( ld->x6_op != 0x2 ) {
+	if (ld->x6_op != 0x2) {
 		/*
 		 * we rely on the macros in unaligned.h for now i.e.,
 		 * we let the compiler figure out how to read memory gracefully.
@@ -767,9 +769,8 @@
 	/*
 	 * check for updates on any kind of loads
 	 */
-	if ( ld->op == 0x5 || ld->m )
-		emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, 
-				ld, regs, ifa);
+	if (ld->op == 0x5 || ld->m)
+		emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
 
 	/*
 	 * handling of various loads (based on EAS2.4):
@@ -882,7 +883,7 @@
 	 *
 	 * Note: the first argument is ignored 
 	 */
-	if ( access_ok(VERIFY_WRITE, (void *)ifa, len) < 0 ) {
+	if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) {
 		DPRINT(("verify area failed on %lx\n",ifa));
 		return -1;
 	}
@@ -926,7 +927,7 @@
 	 * ld->r3 can never be r0, because r0 would not generate an 
 	 * unaligned access.
 	 */
-	if ( ld->op == 0x5 ) {
+	if (ld->op == 0x5) {
 		unsigned long imm;
 
 		/*
@@ -936,7 +937,7 @@
 		/*
 		 * sign extend (8bits) if m set
 		 */
-		if ( ld->m ) imm |= SIGN_EXT9; 
+		if (ld->m) imm |= SIGN_EXT9; 
 		/*
 		 * ifa == r3 (NaT is necessarily cleared)
 		 */
@@ -955,7 +956,8 @@
 	/*
 	 * stX.rel: use fence instead of release
 	 */
-	if ( ld->x6_op == 0xd ) mb();
+	if (ld->x6_op == 0xd)
+		mb();
 
 	return 0;
 }
@@ -1033,7 +1035,7 @@
 	struct ia64_fpreg fpr_final[2];
 	unsigned long len = float_fsz[ld->x6_sz];
 
-	if ( access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0 ) {
+	if (access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0) {
 		DPRINT(("verify area failed on %lx\n", ifa));
 		return -1;
 	}
@@ -1055,7 +1057,7 @@
 	 * ldfpX.a: we don't try to emulate anything but we must
 	 * invalidate the ALAT entry and execute updates, if any.
 	 */
-	if ( ld->x6_op != 0x2 ) {
+	if (ld->x6_op != 0x2) {
 		/*
 		 * does the unaligned access
 		 */
@@ -1118,7 +1120,7 @@
 	 * Check for updates: only immediate updates are available for this
 	 * instruction.
 	 */
-	if ( ld->m ) {
+	if (ld->m) {
 
 		/*
 		 * the immediate is implicit given the ldsz of the operation:
@@ -1132,8 +1134,9 @@
 		 * as long as we don't come here with a ldfpX.s.
 		 * For this reason we keep this sanity check
 		 */
-		if ( ld->x6_op == 1 || ld->x6_op == 3 ) {
-			printk(KERN_ERR "%s: register update on speculative load pair, error\n", __FUNCTION__);	
+		if (ld->x6_op == 1 || ld->x6_op == 3) {
+			printk(KERN_ERR "%s: register update on speculative load pair, error\n",
+			       __FUNCTION__);	
 		}
 
 
@@ -1143,7 +1146,7 @@
 	/*
 	 * Invalidate ALAT entries, if any, for both registers.
 	 */
-	if ( ld->x6_op == 0x2 ) {
+	if (ld->x6_op == 0x2) {
 		invala_fr(ld->r1);
 		invala_fr(ld->imm);
 	}
@@ -1160,10 +1163,10 @@
 
 	/*
 	 * check for load pair because our masking scheme is not fine grain enough
-	if ( ld->x == 1 ) return emulate_load_floatpair(ifa,ld,regs);
+	if (ld->x == 1) return emulate_load_floatpair(ifa,ld,regs);
 	 */
 
-	if ( access_ok(VERIFY_READ, (void *)ifa, len) < 0 ) {
+	if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) {
 		DPRINT(("verify area failed on %lx\n", ifa));
 		return -1;
 	}
@@ -1187,7 +1190,7 @@
 	 * invalidate the ALAT entry.
 	 * See comments in ldX for descriptions on how the various loads are handled.
 	 */
-	if ( ld->x6_op != 0x2 ) {
+	if (ld->x6_op != 0x2) {
 
 		/*
 		 * does the unaligned access
@@ -1243,7 +1246,7 @@
 	/*
 	 * check for updates on any loads
 	 */
-	if ( ld->op == 0x7 || ld->m )
+	if (ld->op == 0x7 || ld->m)
 		emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, 
 				ld, regs, ifa);
 
@@ -1274,7 +1277,7 @@
 	 *
 	 * Note: the first argument is ignored 
 	 */
-	if ( access_ok(VERIFY_WRITE, (void *)ifa, len) < 0 ) {
+	if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) {
 		DPRINT(("verify area failed on %lx\n",ifa));
 		return -1;
 	}
@@ -1342,7 +1345,7 @@
 	 * ld->r3 can never be r0, because r0 would not generate an 
 	 * unaligned access.
 	 */
-	if ( ld->op == 0x7 ) {
+	if (ld->op == 0x7) {
 		unsigned long imm;
 
 		/*
@@ -1352,7 +1355,8 @@
 		/*
 		 * sign extend (8bits) if m set
 		 */
-		if ( ld->m ) imm |= SIGN_EXT9; 
+		if (ld->m)
+			imm |= SIGN_EXT9; 
 		/*
 		 * ifa == r3 (NaT is necessarily cleared)
 		 */
@@ -1384,6 +1388,28 @@
 	load_store_t *insn;
 	int ret = -1;
 
+	/*
+	 * Unaligned references in the kernel could come from unaligned
+	 *   arguments to system calls.  We fault the user process in
+	 *   these cases and panic the kernel otherwise (the kernel should
+	 *   be fixed to not make unaligned accesses).
+	 */
+	if (!user_mode(regs)) {
+		const struct exception_table_entry *fix;
+
+		fix = search_exception_table(regs->cr_iip);
+		if (fix) {
+			regs->r8 = -EFAULT;
+			if (fix->skip & 1) {
+				regs->r9 = 0;
+			}
+			regs->cr_iip += ((long) fix->skip) & ~15;
+			regs->cr_ipsr &= ~IA64_PSR_RI;	/* clear exception slot number */
+			return;
+		}
+		die_if_kernel("Unaligned reference while in kernel\n", regs, 30);
+		/* NOT_REACHED */
+	}
 	if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) {
 		struct siginfo si;
 
@@ -1539,7 +1565,7 @@
 	}
 
 	DPRINT(("ret=%d\n", ret));
-	if ( ret ) {
+	if (ret) {
 		lock_kernel();
 	        force_sig(SIGSEGV, current);
 	        unlock_kernel();
@@ -1549,7 +1575,8 @@
 	 	 * because a memory access instruction (M) can never be in the 
 	 	 * last slot of a bundle. But let's keep it for  now.
 	 	 */
-		if ( ipsr->ri == 2 ) regs->cr_iip += 16;
+		if (ipsr->ri == 2)
+			regs->cr_iip += 16;
 		ipsr->ri = ++ipsr->ri & 3;
 	}
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S
--- v2.3.99-pre5/linux/arch/ia64/lib/clear_user.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/lib/clear_user.S	Fri Apr 21 15:21:24 2000
@@ -210,6 +210,7 @@
 	// 	if p7 -> coming from st4 or st1 : len3 contains what's left
 	// We must restore lc/pr even though might not have been used.
 .Lexit2:
+	.pred.rel "mutex", p6, p7
 (p6)	mov len=len2
 (p7)	mov len=len3
 	;;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S
--- v2.3.99-pre5/linux/arch/ia64/lib/strlen.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/lib/strlen.S	Fri Apr 21 15:21:24 2000
@@ -186,6 +186,7 @@
 	;;
 	cmp.eq p6,p0=8,val1	// val1==8 ?
 (p6)	br.wtop.dptk.few 2b	// loop until p6 == 0
+	;;			// (avoid WAW on p63)
 	sub ret0=base,orig	// distance from base
 	sub tmp=8,val1
 	mov pr=saved_pr,0xffffffffffff0000
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c
--- v2.3.99-pre5/linux/arch/ia64/mm/fault.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/mm/fault.c	Mon Apr 24 15:52:23 2000
@@ -94,7 +94,7 @@
 	 * sure we exit gracefully rather than endlessly redo the
 	 * fault.
 	 */
-	if (!handle_mm_fault(current, vma, address, (isr & IA64_ISR_W) != 0)) {
+	if (!handle_mm_fault(mm, vma, address, (isr & IA64_ISR_W) != 0)) {
 		/*
 		 * We ran out of memory, or some other thing happened
 		 * to us that made us unable to handle the page fault
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c
--- v2.3.99-pre5/linux/arch/ia64/mm/init.c	Fri Mar 10 16:40:40 2000
+++ linux/arch/ia64/mm/init.c	Fri Apr 21 15:21:24 2000
@@ -237,6 +237,7 @@
 	if (!PageReserved(page))
 		printk("put_gate_page: gate page at 0x%lx not in reserved memory\n",
 		       page_address(page));
+
 	pgd = pgd_offset_k(address);		/* note: this is NOT pgd_offset()! */
 	pmd = pmd_alloc(pgd, address);
 	if (!pmd) {
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c
--- v2.3.99-pre5/linux/arch/ia64/mm/tlb.c	Fri Mar 10 16:40:40 2000
+++ linux/arch/ia64/mm/tlb.c	Fri Apr 21 15:21:24 2000
@@ -138,7 +138,7 @@
 			 */
 			++nbits;
 		if (((1UL << nbits) & SUPPORTED_PGBITS) == 0)
-		  panic("flush_tlb_range: BUG: nbits=%lu\n", nbits);
+			panic("flush_tlb_range: BUG: nbits=%lu\n", nbits);
 	}
 	start &= ~((1UL << nbits) - 1);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/tools/Makefile linux/arch/ia64/tools/Makefile
--- v2.3.99-pre5/linux/arch/ia64/tools/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/tools/Makefile	Fri Apr 21 15:21:24 2000
@@ -8,6 +8,8 @@
 
 all: 
 
+mrproper:
+
 clean:
 	rm -f print_offsets.s print_offsets offsets.h
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c
--- v2.3.99-pre5/linux/arch/ia64/tools/print_offsets.c	Sun Feb 13 19:29:03 2000
+++ linux/arch/ia64/tools/print_offsets.c	Fri Apr 21 15:21:24 2000
@@ -12,6 +12,8 @@
  * file, be sure to verify that the awk procedure still works (see
  * prin_offsets.awk).
  */
+#include <linux/config.h>
+
 #include <linux/sched.h>
 
 #include <asm-ia64/processor.h>
@@ -50,6 +52,9 @@
     { "IA64_TASK_PROCESSOR_OFFSET",	offsetof (struct task_struct, processor) },
     { "IA64_TASK_THREAD_OFFSET",	offsetof (struct task_struct, thread) },
     { "IA64_TASK_THREAD_KSP_OFFSET",	offsetof (struct task_struct, thread.ksp) },
+#ifdef CONFIG_IA32_SUPPORT
+    { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) },
+#endif
     { "IA64_TASK_PID_OFFSET",		offsetof (struct task_struct, pid) },
     { "IA64_TASK_MM_OFFSET",		offsetof (struct task_struct, mm) },
     { "IA64_PT_REGS_CR_IPSR_OFFSET",	offsetof (struct pt_regs, cr_ipsr) },
@@ -63,6 +68,8 @@
     { "IA64_SIGCONTEXT_FLAGS_OFFSET",	offsetof (struct sigcontext, sc_flags) },
     { "IA64_SIGCONTEXT_CFM_OFFSET",	offsetof (struct sigcontext, sc_cfm) },
     { "IA64_SIGCONTEXT_FR6_OFFSET",	offsetof (struct sigcontext, sc_fr[6]) },
+    { "IA64_CLONE_VFORK",		CLONE_VFORK },
+    { "IA64_CLONE_VM",			CLONE_VM },
 };
 
 static const char *tabs = "\t\t\t\t\t\t\t\t\t\t";
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S
--- v2.3.99-pre5/linux/arch/ia64/vmlinux.lds.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/vmlinux.lds.S	Fri Apr 21 15:21:24 2000
@@ -8,7 +8,7 @@
 ENTRY(_start)
 SECTIONS
 {
-  v = PAGE_OFFSET;	/* this symbol is here to make debugging with kdb easier... */
+  v = PAGE_OFFSET;	/* this symbol is here to make debugging easier... */
 
   . = KERNEL_START;
 
@@ -38,21 +38,6 @@
   __ex_table : AT(ADDR(__ex_table) - PAGE_OFFSET)
 	{ *(__ex_table) }
   __stop___ex_table = .;
-
-#if defined(CONFIG_KDB)
-  /* Kernel symbols and strings for kdb */
-# define KDB_MEAN_SYMBOL_SIZE	48
-# define KDB_SPACE		(CONFIG_KDB_STBSIZE * KDB_MEAN_SYMBOL_SIZE)
-  . = ALIGN(8);
-  _skdb = .;
-  .kdb : AT(ADDR(.kdb) - PAGE_OFFSET)
-    {
-	*(kdbsymtab)
-	*(kdbstrings)
-    }
-  _ekdb = .;
-  . = _skdb + KDB_SPACE;
-#endif
 
   /* Kernel symbol names for modules: */
   .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.3.99-pre5/linux/arch/m68k/mm/fault.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/mm/fault.c	Mon Apr 24 15:51:29 2000
@@ -99,7 +99,7 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	fault = handle_mm_fault(current, vma, address, write);
+	fault = handle_mm_fault(mm, vma, address, write);
 	if (fault < 0)
 		goto out_of_memory;
 	if (!fault)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c
--- v2.3.99-pre5/linux/arch/mips/baget/vacserial.c	Sat Feb 26 22:31:39 2000
+++ linux/arch/mips/baget/vacserial.c	Fri Apr 21 15:17:57 2000
@@ -2168,7 +2168,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.3.99-pre5/linux/arch/mips/kernel/irixelf.c	Mon Mar 27 08:08:22 2000
+++ linux/arch/mips/kernel/irixelf.c	Thu Apr 13 08:11:48 2000
@@ -717,16 +717,8 @@
 	set_fs(old_fs);
 
 	kfree(elf_phdata);
-	current->personality = PER_IRIX32;
-
-	put_exec_domain(current->exec_domain);
-	if (current->binfmt && current->binfmt->module)
-		__MOD_DEC_USE_COUNT(current->binfmt->module);
-	current->exec_domain = lookup_exec_domain(current->personality);
-	current->binfmt = &irix_format;
-	if (current->binfmt && current->binfmt->module)
-		__MOD_INC_USE_COUNT(current->binfmt->module);
-
+	set_personality(PER_IRIX32);
+	set_binfmt(&irix_format);
 	compute_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
 	bprm->p = (unsigned long) 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.3.99-pre5/linux/arch/mips/kernel/sysirix.c	Tue Apr 11 15:09:13 2000
+++ linux/arch/mips/kernel/sysirix.c	Wed Apr 26 09:25:17 2000
@@ -533,7 +533,7 @@
 	int ret;
 
 	lock_kernel();
-	if (brk < current->mm->end_code) {
+	if (brk < mm->end_code) {
 		ret = -ENOMEM;
 		goto out;
 	}
@@ -549,9 +549,9 @@
 	/*
 	 * Always allow shrinking brk
 	 */
-	if (brk <= current->mm->brk) {
+	if (brk <= mm->brk) {
 		mm->brk = brk;
-		do_munmap(newbrk, oldbrk-newbrk);
+		do_munmap(mm, newbrk, oldbrk-newbrk);
 		ret = 0;
 		goto out;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.3.99-pre5/linux/arch/mips/mm/fault.c	Sat Feb 26 22:31:41 2000
+++ linux/arch/mips/mm/fault.c	Mon Apr 24 15:50:04 2000
@@ -91,7 +91,7 @@
 	 * the fault.
 	 */
 	{
-		int fault = handle_mm_fault(tsk, vma, address, write);
+		int fault = handle_mm_fault(mm, vma, address, write);
 		if (fault < 0)
 			goto out_of_memory;
 		if (!fault)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips64/mm/fault.c linux/arch/mips64/mm/fault.c
--- v2.3.99-pre5/linux/arch/mips64/mm/fault.c	Sat Feb 26 22:31:41 2000
+++ linux/arch/mips64/mm/fault.c	Mon Apr 24 15:52:34 2000
@@ -94,7 +94,7 @@
 	 * the fault.
 	 */
 	{
-		int fault = handle_mm_fault(tsk, vma, address, write);
+		int fault = handle_mm_fault(mm, vma, address, write);
 		if (fault < 0)
 			goto out_of_memory;
 		if (!fault)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.3.99-pre5/linux/arch/ppc/8xx_io/uart.c	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/8xx_io/uart.c	Fri Apr 21 15:17:57 2000
@@ -2063,7 +2063,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.99-pre5/linux/arch/ppc/defconfig	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/defconfig	Thu Apr 13 22:54:26 2000
@@ -184,8 +184,8 @@
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/apus_setup.c	Sat Feb 26 22:31:41 2000
+++ linux/arch/ppc/kernel/apus_setup.c	Tue Apr 25 17:58:46 2000
@@ -108,18 +108,6 @@
 #ifdef CONFIG_HEARTBEAT
 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;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/chrp_setup.c	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Apr 24 13:39:36 2000
@@ -422,10 +422,10 @@
 	request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
 		    xmon_irq, 0, "NMI", 0);
 #endif	/* CONFIG_XMON */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	request_irq(openpic_to_irq(OPENPIC_VEC_IPI),
 		    openpic_ipi_action, 0, "IPI0", 0);
-#endif	/* __SMP__ */
+#endif	/* CONFIG_SMP */
 }
 
 void __init
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/gemini_prom.S linux/arch/ppc/kernel/gemini_prom.S
--- v2.3.99-pre5/linux/arch/ppc/kernel/gemini_prom.S	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/gemini_prom.S	Mon Apr 24 13:39:36 2000
@@ -10,6 +10,7 @@
 
 #include "ppc_asm.tmpl"
 #include "ppc_defs.h"
+#include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/gemini.h>
@@ -25,7 +26,7 @@
 
 _GLOBAL(prom_init)
 _GLOBAL(gemini_prom_init)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Since the MMU's on, get stuff in rom space that we'll need */
 	lis	r4,GEMINI_CPUSTAT@h
 	ori	r4,r4,GEMINI_CPUSTAT@l
@@ -74,14 +75,14 @@
 	addi	r3,r3,1
 	bdnz	3b
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* The 750 book (and Mot/IBM support) says that this will "assist" snooping
 	   when in SMP.  Not sure yet whether this should stay or leave... */
 	mfspr	r4,HID0
 	ori	r4,r4,HID0_ABE
 	mtspr	HID0,r4
 	sync
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	blr
 
 /*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/gemini_setup.c	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/gemini_setup.c	Mon Apr 24 13:39:36 2000
@@ -303,7 +303,7 @@
 
 		/* standard stuff */
 		cache |= ((1<<reg)<<25);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		/* A couple errata for the 750's (both IBM and Motorola silicon)
 		   note that you can get missed cache lines on MP implementations.
 		   The workaround - if you call it that - is to make the L2
@@ -351,7 +351,7 @@
 	for( i=0; i < NR_IRQS; i++ ) 
 		irq_desc[i].handler = &open_pic;
 	openpic_init(1);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
  	request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
  		    0, "IPI0", 0);
  	request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
@@ -360,7 +360,7 @@
  		    0, "IPI2 (stop CPU)", 0);
  	request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
  		    0, "IPI3 (reschedule)", 0);
-#endif	/* __SMP__ */
+#endif	/* CONFIG_SMP */
 }
 
 #define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/hashtable.S linux/arch/ppc/kernel/hashtable.S
--- v2.3.99-pre5/linux/arch/ppc/kernel/hashtable.S	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/hashtable.S	Mon Apr 24 13:39:36 2000
@@ -52,7 +52,7 @@
 	
 	.globl	hash_page
 hash_page:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	SAVE_2GPRS(7,r21)
 	eieio
 	lis	r2,hash_table_lock@h
@@ -88,7 +88,7 @@
 	rlwimi	r5,r3,12,20,29		/* insert top 10 bits of address */
 	lwz	r5,0(r5)		/* get pmd entry */
 	rlwinm.	r5,r5,0,0,19		/* extract address of pte page */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	beq-	hash_page_out		/* return if no mapping */
 #else
 	/* XXX it seems like the 601 will give a machine fault on the
@@ -102,7 +102,7 @@
 	lwz	r6,0(r2)		/* get linux-style pte */
 	ori	r4,r4,1			/* set _PAGE_PRESENT bit in access */
 	andc.	r0,r4,r6		/* check access & ~permission */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	bne-	hash_page_out		/* return if access not permitted */
 #else
 	bnelr-
@@ -128,7 +128,7 @@
 	rlwinm	r5,r5,7,1,24		/* put VSID in 0x7fffff80 bits */
 #endif /* CONFIG_PPC64 */
 	
-#ifndef __SMP__				/* do this later for SMP */
+#ifndef CONFIG_SMP				/* do this later for SMP */
 #ifdef CONFIG_PPC64
 	ori	r5,r5,1			/* set V (valid) bit */
 #else /* CONFIG_PPC64 */
@@ -280,7 +280,7 @@
 	addi	r4,r4,1
 	stw	r4,htab_evicts@l(r2)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	/* Store PTE in PTEG */
 found_empty:
 #ifdef CONFIG_PPC64
@@ -296,7 +296,7 @@
 #endif	
 	sync
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 /*
  * Between the tlbie above and updating the hash table entry below,
  * another CPU could read the hash table entry and put it in its TLB.
@@ -324,7 +324,7 @@
 	sync
 	oris	r5,r5,0x8000
 	stw	r5,0(r3)	/* finally set V bit in PTE */
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 /*
  * Update the hash table miss count.  We only want misses here
@@ -342,7 +342,7 @@
 	addi	r3,r3,1
 	stw	r3,htab_reloads@l(r2)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	lis	r2,hash_table_lock@ha
 	tophys(r2,r2)
 	li	r0,0
@@ -373,7 +373,7 @@
 	lwz	r21,GPR21(r21)
 	rfi
 	
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 hash_page_out:
 	lis	r2,hash_table_lock@ha
 	tophys(r2,r2)
@@ -386,7 +386,7 @@
 	.globl	hash_table_lock
 hash_table_lock:
 	.long	0
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 	.data
 next_slot:
@@ -404,13 +404,13 @@
 	bne+	99f
 	tlbia
 	sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync
 	sync
 #endif
 	blr
 99:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Note - we had better not do anything which could generate
 	   a hash table miss while we have the hash table locked,
 	   or we'll get a deadlock.  -paulus */
@@ -451,7 +451,7 @@
 	sync
 	tlbia
 	sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync
 	sync
 	lis	r3,hash_table_lock@ha
@@ -473,13 +473,13 @@
 	bne+	99f
 	tlbie	r4			/* in hw tlb too */
 	sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync
 	sync
 #endif
 	blr
 99:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Note - we had better not do anything which could generate
 	   a hash table miss while we have the hash table locked,
 	   or we'll get a deadlock.  -paulus */
@@ -531,7 +531,7 @@
 4:	sync
 	tlbie	r4			/* in hw tlb too */
 	sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync
 	sync
 	li	r0,0
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.99-pre5/linux/arch/ppc/kernel/head.S	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/kernel/head.S	Mon Apr 24 13:39:36 2000
@@ -189,11 +189,11 @@
 #endif /* CONFIG_PPC64 */
 
 4:	tophys(r8,r11)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	ori	r8,r8,0x12		/* R/W access, M=1 */
 #else
 	ori	r8,r8,2			/* R/W access */
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 #ifdef CONFIG_APUS
 	ori	r11,r11,BL_8M<<2|0x2	/* set up 8MB BAT registers for 604 */
 #else
@@ -782,7 +782,7 @@
  * horrendously complex, especially when a task switches from one CPU
  * to another.  Instead we call giveup_fpu in switch_to.
  */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	lis	r6,0                    /* get __pa constant */
 	tophys(r6,r6)
 	addis	r3,r6,last_task_used_math@ha
@@ -801,18 +801,18 @@
 	andc	r4,r4,r20		/* disable FP for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	/* enable use of FP after return */
 	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
 	lfd	fr0,THREAD_FPSCR-4(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	subi	r4,r5,THREAD
 	sub	r4,r4,r6
 	stw	r4,last_task_used_math@l(r3)
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	/* restore registers and return */
 	lwz	r3,_CCR(r21)
 	lwz	r4,_LINK(r21)
@@ -868,7 +868,7 @@
  * horrendously complex, especially when a task switches from one CPU
  * to another.  Instead we call giveup_altivec in switch_to.
  */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 #ifndef CONFIG_APUS
 	lis	r6,-KERNELBASE@h
 #else
@@ -892,7 +892,7 @@
 	andc	r4,r4,r20	/* disable altivec for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	/* enable use of AltiVec after return */
 	oris	r23,r23,MSR_VEC@h
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
@@ -900,11 +900,11 @@
 	LVX(vr0,r20,r5)
 	MTVSCR(vr0)
 	REST_32VR(0,r20,r5)
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	subi	r4,r5,THREAD
 	sub	r4,r4,r6
 	stw	r4,last_task_used_altivec@l(r3)
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	/* restore registers and return */
 	lwz	r3,_CCR(r21)
 	lwz	r4,_LINK(r21)
@@ -967,11 +967,11 @@
 	andc	r4,r4,r3		/* disable AltiVec for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	li	r5,0
 	lis	r4,last_task_used_altivec@ha
 	stw	r5,last_task_used_altivec@l(r4)
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	blr
 #endif /* CONFIG_ALTIVEC */
 	
@@ -1002,11 +1002,11 @@
 	andc	r4,r4,r3		/* disable FP for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	li	r5,0
 	lis	r4,last_task_used_math@ha
 	stw	r5,last_task_used_math@l(r4)
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	blr
 
 /*
@@ -1432,7 +1432,7 @@
 	SYNC			/* Force all PTE updates to finish */
 	tlbia			/* Clear all TLB entries */
 	sync			/* wait for tlbia/tlbie to finish */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync			/* ... on all CPUs */
 	sync
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S
--- v2.3.99-pre5/linux/arch/ppc/kernel/head_8xx.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/ppc/kernel/head_8xx.S	Mon Apr 24 13:39:36 2000
@@ -698,7 +698,7 @@
  * This is where the main kernel code starts.
  */
 start_here:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* if we're the second cpu stack and r2 are different
 	* and we want to not clear the bss -- Cort */
 	lis	r5,first_cpu_booted@h
@@ -715,7 +715,7 @@
 	lwz	r2,0(r2)
 	b	10f
 99:	
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	/* ptr to current */
 	lis	r2,init_task_union@h
 	ori	r2,r2,init_task_union@l
@@ -734,9 +734,9 @@
 3:	stwu	r0,4(r8)
 	bdnz	3b
 2:
-#ifdef __SMP__	
+#ifdef CONFIG_SMP	
 10:
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	/* stack */
 	addi	r1,r2,TASK_UNION_SIZE
 	li	r0,0
@@ -779,7 +779,7 @@
 	SYNC			/* Force all PTE updates to finish */
 	tlbia			/* Clear all TLB entries */
 	sync			/* wait for tlbia/tlbie to finish */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync			/* ... on all CPUs */
 	sync
 #endif
@@ -794,7 +794,7 @@
 	li	r4,MSR_KERNEL
 	lis	r3,start_kernel@h
 	ori	r3,r3,start_kernel@l
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* the second time through here we go to
 	 * start_secondary(). -- Cort
 	 */
@@ -807,7 +807,7 @@
 	lis	r3,start_secondary@h
 	ori	r3,r3,start_secondary@l
 10:	
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
 	rfi			/* enable MMU and jump to start_kernel */
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/idle.c	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/idle.c	Mon Apr 24 13:39:36 2000
@@ -61,7 +61,7 @@
 		if ( !current->need_resched && htab_reclaim_on ) htab_reclaim();
 		if ( !current->need_resched ) power_save();
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		if (current->need_resched)
 #endif
 			schedule();
@@ -162,11 +162,11 @@
 			: "=&r" (tmp), "=&r" (page), "+m" (zero_cache)
 			: "r" (&zero_quicklist)
 			: "cc" );
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		/* if another cpu beat us above this can happen -- Cort */
 		if ( page == 0 ) 
 			return 0;
-#endif /* __SMP__ */		
+#endif /* CONFIG_SMP */		
 		/* we can update zerocount after the fact since it is not
 		 * used for anything but control of a loop which doesn't
 		 * matter since it won't affect anything if it zeros one
@@ -253,7 +253,7 @@
 		/* atomically add this page to the list */
 		asm (	"101:lwarx  %0,0,%2\n"  /* reserve zero_cache */
 			"    stw    %0,0(%3)\n" /* update *pageptr */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 			"    sync\n"            /* let store settle */
 #endif			
 			"    stwcx. %3,0,%2\n"  /* update zero_cache in mem */
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/irq.c	Fri Mar 10 16:40:40 2000
+++ linux/arch/ppc/kernel/irq.c	Mon Apr 24 13:39:36 2000
@@ -237,13 +237,13 @@
 		if ( !action || !action->handler )
 			continue;
 		len += sprintf(buf+len, "%3d: ", i);		
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		for (j = 0; j < smp_num_cpus; j++)
 			len += sprintf(buf+len, "%10u ",
 				kstat.irqs[cpu_logical_map(j)][i]);
 #else		
 		len += sprintf(buf+len, "%10u ", kstat_irqs(i));
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 		if ( irq_desc[i].handler )		
 			len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
 		else
@@ -254,7 +254,7 @@
 		}
 		len += sprintf(buf+len, "\n");
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* should this be per processor send/receive? */
 	len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
 #endif		
@@ -343,7 +343,7 @@
 	ppc_md.init_IRQ();
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 unsigned char global_irq_holder = NO_PROC_ID;
 unsigned volatile int global_irq_lock;
 atomic_t global_irq_count;
@@ -611,7 +611,7 @@
 	}
 	}
 }
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 static struct proc_dir_entry * root_irq_dir;
 static struct proc_dir_entry * irq_dir [NR_IRQS];
@@ -733,7 +733,7 @@
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
 	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
 
 	entry->nlink = 1;
 	entry->data = (void *)irq;
@@ -754,7 +754,7 @@
 	root_irq_dir = proc_mkdir("irq", 0);
 
 	/* create /proc/irq/prof_cpu_mask */
-	entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
 
 	entry->nlink = 1;
 	entry->data = (void *)&prof_cpu_mask;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.99-pre5/linux/arch/ppc/kernel/misc.S	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/misc.S	Mon Apr 24 13:39:36 2000
@@ -142,7 +142,7 @@
 	sync
 	tlbia
 	sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync
 	sync
 #endif
@@ -154,7 +154,7 @@
 _GLOBAL(_tlbie)
 	tlbie	r3
 	sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync
 	sync
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/open_pic.c	Fri Mar 10 16:40:40 2000
+++ linux/arch/ppc/kernel/open_pic.c	Mon Apr 24 13:39:36 2000
@@ -101,12 +101,12 @@
 {
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
 	smp_message_recv(cpl-OPENPIC_VEC_IPI);
 }
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #ifdef __i386__
 static inline u_int in_le32(volatile u_int *addr)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/pmac_pic.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/kernel/pmac_pic.c	Mon Apr 24 13:39:36 2000
@@ -183,7 +183,7 @@
 	int irq;
 	unsigned long bits = 0;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	void pmac_smp_message_recv(void);
 	
         /* IPI's are a hack on the powersurge -- Cort */
@@ -197,7 +197,7 @@
 		pmac_smp_message_recv();
 		return -2;	/* ignore, already handled */
         }
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 	/* Yeah, I know, this could be a separate get_irq function */
 	if (has_openpic)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/ppc_ksyms.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Mon Apr 24 13:39:36 2000
@@ -35,9 +35,9 @@
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/hw_irq.h>
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #include <asm/smplock.h>
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 #include "time.h"
 
 /* Tell string.h we don't want memcpy etc. as cpp defines */
@@ -76,9 +76,9 @@
 EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(local_bh_count);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(kernel_flag);
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
 EXPORT_SYMBOL(isa_io_base);
@@ -189,7 +189,7 @@
 EXPORT_SYMBOL(enable_kernel_fp);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(xchg_u32);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/prep_setup.c	Wed Dec 29 13:13:13 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Apr 24 13:39:36 2000
@@ -118,7 +118,7 @@
 	extern char *Motherboard_map_name;
 	int len, i;
   
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define CD(X)		(cpu_data[n].X)  
 #else
 #define CD(X) (X)
@@ -624,10 +624,10 @@
         for ( i = 0 ; i < 16  ; i++ )
                 irq_desc[i].handler = &i8259_pic;
         i8259_init();
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
 		    0, "IPI0", 0);
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/process.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/process.c	Mon Apr 24 13:39:36 2000
@@ -154,7 +154,7 @@
 void 
 enable_kernel_altivec(void)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
 		giveup_altivec(current);
 	else
@@ -169,14 +169,14 @@
 void
 enable_kernel_fp(void)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
 		giveup_fpu(current);
 	else
 		giveup_fpu(NULL);	/* just enables FP for kernel */
 #else
 	giveup_fpu(last_task_used_math);
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 }
 
 int
@@ -208,7 +208,7 @@
 	       new->comm,new->pid,new->thread.regs->nip,new->processor,
 	       new->fs->root,prev->fs->root);
 #endif
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* avoid complexity of lazy save/restore of fpu
 	 * by just saving it every time we switch out if
 	 * this task used the fpu during the last quantum.
@@ -236,7 +236,7 @@
 #endif /* CONFIG_ALTIVEC */	
 	prev->last_processor = prev->processor;
 	current_set[smp_processor_id()] = new;
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	/* Avoid the trap.  On smp this this never happens since
 	 * we don't set last_task_used_altivec -- Cort
 	 */
@@ -265,9 +265,9 @@
 	printk("\nlast math %p last altivec %p", last_task_used_math,
 	       last_task_used_altivec);
 	
-#ifdef __SMP__	
+#ifdef CONFIG_SMP
 	printk(" CPU: %d last CPU: %d", current->processor,current->last_processor);
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	
 	printk("\n");
 	for (i = 0;  i < 32;  i++)
@@ -319,7 +319,7 @@
 {
 	unsigned long msr;
 	struct pt_regs * childregs, *kregs;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	extern void ret_from_smpfork(void);
 #else
 	extern void ret_from_except(void);
@@ -336,7 +336,7 @@
 	p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
 	p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
 	kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	kregs->nip = (unsigned long)ret_from_smpfork;
 #else	
 	kregs->nip = (unsigned long)ret_from_except;
@@ -378,9 +378,9 @@
 	childregs->msr &= ~MSR_VEC;
 #endif /* CONFIG_ALTIVEC */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	p->last_processor = NO_PROC_ID;
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	return 0;
 }
 
@@ -447,14 +447,14 @@
 	int res;
 	lock_kernel();
 	res = do_fork(clone_flags, regs->gpr[1], regs);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* When we clone the idle task we keep the same pid but
 	 * the return value of 0 for both causes problems.
 	 * -- Cort
 	 */
 	if ((current->pid == 0) && (current == &init_task))
 		res = 1;
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	unlock_kernel();
 	return res;
 }
@@ -466,14 +466,14 @@
 	int res;
 	
 	res = do_fork(SIGCHLD, regs->gpr[1], regs);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* When we clone the idle task we keep the same pid but
 	 * the return value of 0 for both causes problems.
 	 * -- Cort
 	 */
 	if ((current->pid == 0) && (current == &init_task))
 		res = 1;
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	return res;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/ptrace.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/ptrace.c	Mon Apr 24 15:50:54 2000
@@ -100,7 +100,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
+		handle_mm_fault(tsk->mm, vma, addr, 0);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -110,7 +110,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir,addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
+		handle_mm_fault(tsk->mm, vma, addr, 0);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -120,7 +120,7 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
+		handle_mm_fault(tsk->mm, vma, addr, 0);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
@@ -151,7 +151,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
+		handle_mm_fault(tsk->mm, vma, addr, 1);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -161,7 +161,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir,addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
+		handle_mm_fault(tsk->mm, vma, addr, 1);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -171,12 +171,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
+		handle_mm_fault(tsk->mm, vma, addr, 1);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
+		handle_mm_fault(tsk->mm, vma, addr, 1);
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -198,7 +198,7 @@
 static int read_long(struct task_struct * tsk, unsigned long addr,
 	unsigned long * result)
 {
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+	struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr);
 
 	if (!vma)
 		return -EIO;
@@ -240,7 +240,7 @@
 static int write_long(struct task_struct * tsk, unsigned long addr,
 	unsigned long data)
 {
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+	struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr);
 
 	if (!vma)
 		return -EIO;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/setup.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/ppc/kernel/setup.c	Mon Apr 24 13:39:36 2000
@@ -204,7 +204,7 @@
 	unsigned int pvr;
 	unsigned short maj, min;
 	
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define CPU_PRESENT(x) (cpu_callin_map[(x)])
 #define GET_PVR ((long int)(cpu_data[i].pvr))
 #define CD(x) (cpu_data[i].x)
@@ -355,13 +355,13 @@
 		bogosum += CD(loops_per_sec);
 	}
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if ( i )
 		len += sprintf(buffer+len, "\n");
 	len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
 		       (bogosum+2500)/500000,
 		       (bogosum+2500)/5000 % 100);
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 	/*
 	 * Ooh's and aah's info about zero'd pages in idle task
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.3.99-pre5/linux/arch/ppc/kernel/time.c	Tue Jan 11 22:31:38 2000
+++ linux/arch/ppc/kernel/time.c	Mon Apr 24 13:39:36 2000
@@ -74,7 +74,7 @@
 	unsigned long cpu = smp_processor_id();
 	
 	hardirq_enter(cpu);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	{
 		unsigned int loops = 100000000;
 		while (test_bit(0, &global_irq_lock)) {
@@ -93,7 +93,7 @@
 			}
 		}
 	}
-#endif /* __SMP__ */			
+#endif /* CONFIG_SMP */			
 	
 	dval = get_dec();
 	/*
@@ -133,7 +133,7 @@
 				last_rtc_update = xtime.tv_sec;
 		}
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_local_timer_interrupt(regs);
 #endif		
 	
@@ -155,7 +155,7 @@
 	cli();
 	*tv = xtime;
 	/* XXX we don't seem to have the decrementers synced properly yet */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	tv->tv_usec += (decrementer_count - get_dec())
 	    * count_period_num / count_period_den;
 	if (tv->tv_usec >= 1000000) {
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.3.99-pre5/linux/arch/ppc/mm/fault.c	Tue Apr 11 15:09:13 2000
+++ linux/arch/ppc/mm/fault.c	Mon Apr 24 15:50:18 2000
@@ -135,7 +135,7 @@
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	if (!handle_mm_fault(current, vma, address, is_write))
+	if (!handle_mm_fault(mm, vma, address, is_write))
 		goto bad_area;
 	up(&mm->mmap_sem);
 	/*
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.99-pre5/linux/arch/ppc/mm/init.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/ppc/mm/init.c	Mon Apr 24 13:39:36 2000
@@ -87,7 +87,7 @@
 extern int num_memory;
 extern struct mem_info memory[];
 extern boot_infos_t *boot_infos;
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 struct pgtable_cache_struct quicklists;
 #endif
 
@@ -278,9 +278,9 @@
 	show_buffers();
 	printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid",
 	       "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	printk(" %3s", "CPU");
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 	printk("\n");
 	for_each_task(p)
 	{
@@ -294,7 +294,7 @@
 		       (ulong)p);
 		{
 			int iscur = 0;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 			printk("%3d ", p->processor);
 			if ( (p->processor != NO_PROC_ID) &&
 			     (p == current_set[p->processor]) )
@@ -315,7 +315,7 @@
 					printk(",");
 				printk("last math");
 			}			
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 			printk("\n");
 		}
 	}
@@ -495,7 +495,7 @@
 {
 	__clear_user(Hash, Hash_size);
 	_tlbia();
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif	
 }
@@ -511,7 +511,7 @@
 	mm->context = NO_CONTEXT;
 	if (mm == current->mm)
 		activate_mm(mm, mm);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif	
 }
@@ -523,7 +523,7 @@
 		flush_hash_page(vma->vm_mm->context, vmaddr);
 	else
 		flush_hash_page(0, vmaddr);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif	
 }
@@ -551,7 +551,7 @@
 	{
 		flush_hash_page(mm->context, start);
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif	
 }
@@ -575,7 +575,7 @@
 	}
 	read_unlock(&tasklist_lock);
 	flush_hash_segments(0x10, 0xffffff);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif	
 	atomic_set(&next_mmu_context, 0);
@@ -663,7 +663,7 @@
 }
 
 #define IO_PAGE	(_PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_RW)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define RAM_PAGE (_PAGE_RW|_PAGE_COHERENT)
 #else
 #define RAM_PAGE (_PAGE_RW)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/defconfig linux/arch/sh/defconfig
--- v2.3.99-pre5/linux/arch/sh/defconfig	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/defconfig	Mon Apr 24 13:54:17 2000
@@ -54,12 +54,17 @@
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
 
 #
 # Additional Block Devices
 #
 # CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_STRIPED is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 
@@ -122,6 +127,7 @@
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
@@ -135,17 +141,23 @@
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_NCPFS_NLS is not set
 
 #
 # Partition Types
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile
--- v2.3.99-pre5/linux/arch/sh/kernel/Makefile	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/Makefile	Mon Apr 24 13:54:17 2000
@@ -29,7 +29,6 @@
 entry.o: entry.S
 
 head.o: head.S
-	$(CC) $(AFLAGS) -traditional -c $*.S -o $*.o
 
 clean:
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S
--- v2.3.99-pre5/linux/arch/sh/kernel/entry.S	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/entry.S	Mon Apr 24 13:54:17 2000
@@ -14,6 +14,8 @@
 #include <linux/linkage.h>
 #include <linux/config.h>
 
+#define COMPAT_OLD_SYSCALL_ABI 1
+
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
 ! to be jumped is too far, but it causes illegal slot exception.
@@ -31,26 +33,24 @@
  *	if the order here is changed, it needs to be
  *	updated in ptrace.c and ptrace.h
  *
- *	syscall #
- *	ssr
- *	r0
+ *	$r0
  *      ...
- *	r15 = stack pointer
- *	gbr
- *	mach
- *	macl
- *	pr
- *	spc
+ *	$r15 = stack pointer
+ *	$spc
+ *	$pr
+ *	$ssr
+ *	$gbr
+ *	$mach
+ *	$macl
+ *	syscall #
  *
  */
 
 /*
  * These are offsets into the task-struct.
  */
-state		=  0
 flags		=  4
 sigpending	=  8
-addr_limit	= 12
 need_resched	= 20
 
 PF_TRACESYS  = 0x00000020
@@ -75,30 +75,35 @@
 #endif
 
 /* Offsets to the stack */
-SYSCALL_NR =  0
-SR	   =  4
-R0         =  8
-SP	   =  (8+15*4)
+R0         =  0		/* Return value */
+SP	   =  (15*4)
+SR	   =  (16*4+8)
+SYSCALL_NR =  (16*4+6*4)
+
 
 #define k0	r0
 #define k1	r1
 #define k2	r2
 #define k3	r3
+#define k4	r4
 
-#define kernel_sp	r4	/* r4_bank1 */
-#define ksp		r4_bank	/* r4_bank1 */
+#define current		r7	/* r7_bank1 */
+#define g_imask		r6	/* r6_bank1 */
+#define k_current	r7_bank	/* r7_bank1 */
+#define k_g_imask	r6_bank	/* r6_bank1 */
 #define k_ex_code	r2_bank	/* r2_bank1 */
 
-/* Kernel mode register usage:
-	k0	scratch
-	k1	scratch
-	k2	scratch (Exception code)
-	k3	scratch (Return address)
-	k4	Stack base = current+8192
-	k5	Global Interrupt Mask (0--15)
-	k6	reserved
-	k7	reserved
-*/
+/*
+ * Kernel mode register usage:
+ *	k0	scratch
+ *	k1	scratch
+ *	k2	scratch (Exception code)
+ *	k3	scratch (Return address)
+ *	k4	scratch
+ *	k5	reserved
+ *	k6	Global Interrupt Mask (0--15 << 4)
+ *	k7	CURRENT (pointer to current task)
+ */
 
 !
 ! TLB Miss / Initial Page write exception handling
@@ -114,42 +119,60 @@
 ! this first version depends *much* on C implementation.
 !
 
-#define RESTORE_FLAGS()			\
-	mov.l	@(SR,$r15), $r0;	\
-	and	#0xf0, $r0;		\
-	shlr8	$r0;			\
-	cmp/eq	#0x0f, $r0;		\
-	bt	9f;			\
-	mov.l	__INV_IMASK, $r1;	\
-	stc	$sr, $r0;		\
-	and	$r1, $r0;		\
-	stc	$r5_bank, $r1;		\
-	or	$r1, $r0;		\
-	ldc	$r0, $sr
+#define STI()				\
+	mov.l	__INV_IMASK, $r11;	\
+	stc	$sr, $r10;		\
+	and	$r11, $r10;		\
+	stc	$k_g_imask, $r11;	\
+	or	$r11, $r10;		\
+	ldc	$r10, $sr
 
 	.balign	4
-tlb_protection_violation_load:
 tlb_miss_load:
-	mov	#-1, $r0
-	mov.l	$r0, @$r15	! syscall nr = -1
 	mov.l	2f, $r0
 	mov.l	@$r0, $r6
-	RESTORE_FLAGS()
-9:	mov	$r15, $r4
+	STI()
+	mov	$r15, $r4
 	mov.l	1f, $r0
 	jmp	@$r0
 	 mov	#0, $r5
 
 	.balign	4
-tlb_protection_violation_store:
 tlb_miss_store:
+	mov.l	2f, $r0
+	mov.l	@$r0, $r6
+	STI()
+	mov	$r15, $r4
+	mov.l	1f, $r0
+	jmp	@$r0
+	 mov	#1, $r5
+
+	.balign	4
 initial_page_write:
-	mov	#-1, $r0
-	mov.l	$r0, @$r15	! syscall nr = -1
 	mov.l	2f, $r0
 	mov.l	@$r0, $r6
-	RESTORE_FLAGS()
-9:	mov	$r15, $r4
+	STI()
+	mov	$r15, $r4
+	mov.l	1f, $r0
+	jmp	@$r0
+	 mov	#1, $r5
+
+	.balign	4
+tlb_protection_violation_load:
+	mov.l	2f, $r0
+	mov.l	@$r0, $r6
+	STI()
+	mov	$r15, $r4
+	mov.l	1f, $r0
+	jmp	@$r0
+	 mov	#0, $r5
+
+	.balign	4
+tlb_protection_violation_store:
+	mov.l	2f, $r0
+	mov.l	@$r0, $r6
+	STI()
+	mov	$r15, $r4
 	mov.l	1f, $r0
 	jmp	@$r0
 	 mov	#1, $r5
@@ -162,8 +185,6 @@
 	.balign	4
 	/* Unwind the stack and jmp to the debug entry */
 debug:
-	add	#4, $r15	! skip syscall number
-	mov.l	@$r15+, $r11	! SSR
 	mov.l	@$r15+, $r0
 	mov.l	@$r15+, $r1
 	mov.l	@$r15+, $r2
@@ -172,11 +193,10 @@
 	mov.l	@$r15+, $r5
 	mov.l	@$r15+, $r6
 	mov.l	@$r15+, $r7
-	stc	$sr, $r14
-	mov.l	1f, $r9			! BL =1, RB=1
-	or	$r9, $r14
-	ldc	$r14, $sr		! here, change the register bank
-	mov	$r11, $k1
+	stc	$sr, $r8
+	mov.l	1f, $r9			! BL =1, RB=1, IMASK=0x0F
+	or	$r9, $r8
+	ldc	$r8, $sr		! here, change the register bank
 	mov.l	@$r15+, $r8
 	mov.l	@$r15+, $r9
 	mov.l	@$r15+, $r10
@@ -185,11 +205,12 @@
 	mov.l	@$r15+, $r13
 	mov.l	@$r15+, $r14
 	mov.l	@$r15+, $k0
+	ldc.l	@$r15+, $spc
+	lds.l	@$r15+, $pr
+	mov.l	@$r15+, $k1
 	ldc.l	@$r15+, $gbr
 	lds.l	@$r15+, $mach
 	lds.l	@$r15+, $macl
-	lds.l	@$r15+, $pr
-	ldc.l	@$r15+, $spc
 	mov	$k0, $r15
 	!
 	mov.l	2f, $k0
@@ -203,11 +224,10 @@
 	.balign	4
 error:	
 	!
-	RESTORE_FLAGS()
-9:	mov.l	1f, $r1
-	mov	#-1, $r0
-	jmp	@$r1
-	 mov.l	$r0, @$r15		! syscall nr = -1
+	STI()
+	mov.l	1f, $r0
+	jmp	@$r0
+	 nop
 	.balign	4
 1:	.long	SYMBOL_NAME(do_exception_error)
 
@@ -222,76 +242,106 @@
 	bra	SYMBOL_NAME(ret_from_syscall)
 	 add	#4, $r15	! pop down bogus r0 (see switch_to MACRO)
 
-!
-! The immediate value of "trapa" indicates the number of arguments
-! placed on the stack.
-!
-! Note that TRA register contains the value = Imm x 4.
-!
+/*
+ * Old syscall interface:
+ *
+ *	Syscall #: R0
+ *	Arguments #0 to #3: R4--R7
+ *	more arguments: On the stack
+ *	TRA: (number of arguments on the stack) x 4
+ *
+ * New syscall interface:
+ *
+ *	Syscall #: R3
+ *	Arguments #0 to #3: R4--R7
+ *	Arguments #4 to #6: R0, R1, R2
+ *	TRA: (number of arguments + 0x10) x 4
+ *
+ */
+
 system_call:
-	mov.l	1f, $r2
-	mov.l	@$r2, $r8
-	!
-	! DEBUG DEBUG
-	! mov.l	led, $r1
-	! mov	$r0, $r2
-	! mov.b	$r2, @$r1
+	mov.l	1f, $r9
+	mov.l	@$r9, $r8
 	!
 #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
-	mov	#0x20, $r1
-	extu.b	$r1, $r1
-	shll2	$r1
-	cmp/hs	$r1, $r8
+	mov	#0x20, $r9
+	extu.b	$r9, $r9
+	shll2	$r9
+	cmp/hs	$r9, $r8
 	bt	debug
 #endif
 	!
-	mov	$r0, $r2
-	RESTORE_FLAGS()
-9:	mov.l	__n_sys, $r1
-	cmp/hs	$r1, $r2
+	mov	#SYSCALL_NR, $r14
+	add	$r15, $r14
+	!
+	mov	#0x40, $r9
+#ifdef COMPAT_OLD_SYSCALL_ABI
+	cmp/hs	$r9, $r8
+	mov	$r0, $r10
+	bf/s	0f
+	 mov	$r0, $r9
+#endif
+	! New Syscall ABI
+	sub	$r9, $r8
+	shlr2	$r8
+	shll8	$r8
+	shll8	$r8
+	mov	$r3, $r10
+	or	$r8, $r10	! Encode syscall # and # of arguments
+	!
+	mov	$r3, $r9
+	mov	#0, $r8
+0:
+	mov.l	$r10, @$r14	! set syscall_nr
+	STI()
+	mov.l	__n_sys, $r10
+	cmp/hs	$r10, $r9
 	bt	badsys
 	!
-	stc	$ksp, $r1
-	mov.l	__tsk_flags, $r0
-	add	$r0, $r1	!
-	mov.l	@$r1, $r0	! Is it trace?
-	tst	#PF_TRACESYS, $r0
+#ifdef COMPAT_OLD_SYSCALL_ABI
+	!				  Build the stack frame if TRA > 0
+	mov	$r8, $r10
+	cmp/pl	$r10
+	bf	0f
+	mov.l	@(SP,$r15), $r0		! get original stack
+7:	add	#-4, $r10
+4:	mov.l	@($r0,$r10), $r1	! May cause address error exception..
+	mov.l	$r1, @-$r15
+	cmp/pl	$r10
+	bt	7b
+#endif
+0:	stc	$k_current, $r11
+	mov.l	@(flags,$r11), $r10	! Is it trace?
+	mov	#PF_TRACESYS, $r11
+	tst	$r11, $r10
 	bt	5f
 	!                     Trace system call
-	mov	#-ENOSYS, $r1
-	mov.l	$r1, @(R0,$r15)
-	mov.l	3f, $r1
-	jsr	@$r1
+	mov	#-ENOSYS, $r11
+	mov.l	$r11, @(R0,$r15)
+	mov.l	2f, $r11
+	jsr	@$r11
 	 nop
-	mova	3f, $r0
+	mov.l	__syscall_ret_trace, $r10
 	bra	6f
-	 lds	$r0, $pr
+	 lds	$r10, $pr
 	!
-5:	mova	syscall_ret, $r0
-	lds	$r0, $pr
-	!				  Build the stack frame if TRA > 0
-6:	mov	$r2, $r3
-	mov	$r8, $r2
-	cmp/pl	$r8
-	bf	0f
-	mov	#SP, $r0
-	mov.l	@($r0,$r15), $r0	! get original stack
-7:	add	#-4, $r8
-4:	mov.l	@($r0,$r8), $r1		! May cause address error exception..
-	mov.l	$r1, @-$r15
-	cmp/pl	$r8
-	bt	7b
+5:	mov.l	__syscall_ret, $r10
+	lds	$r10, $pr
 	!
-0:	mov	$r3, $r0
-	shll2	$r0		! x4
-	mov.l	__sct, $r1
-	add	$r1, $r0
-	mov.l	@$r0, $r1
-	jmp	@$r1
-	 mov	$r2, $r8
+6:	mov	$r9, $r10
+	shll2	$r10		! x4
+	mov.l	__sct, $r11
+	add	$r11, $r10
+	mov.l	@$r10, $r11
+	jmp	@$r11
+	 nop
+
 	! In case of trace
 	.balign	4
-3:	add	$r8, $r15		! pop off the arguments
+3:
+#ifdef COMPAT_OLD_SYSCALL_ABI
+	add	$r8, $r15		! pop off the arguments
+#endif
 	mov.l	$r0, @(R0,$r15)		! save the return value
 	mov.l	2f, $r1
 	mova	SYMBOL_NAME(ret_from_syscall), $r0
@@ -302,9 +352,12 @@
 2:	.long	SYMBOL_NAME(syscall_trace)
 __n_sys:	.long	NR_syscalls
 __sct:		.long	SYMBOL_NAME(sys_call_table)
-__tsk_flags:	.long	flags-8192	! offset from stackbase to tsk->flags
-led:	.long	0xa8000000	! For my board -- gN
+__syscall_ret_trace:
+		.long	3b
+__syscall_ret:
+		.long	SYMBOL_NAME(syscall_ret)
 
+#ifdef COMPAT_OLD_SYSCALL_ABI
 	.section	.fixup,"ax"
 fixup_syscall_argerr:
 	rts
@@ -316,6 +369,7 @@
 	.balign	4
 	.long	4b,fixup_syscall_argerr
 .previous
+#endif
 
 	.balign	4
 reschedule:
@@ -327,23 +381,25 @@
 1:	.long	SYMBOL_NAME(schedule)
 
 ENTRY(ret_from_irq)
-	mov.l	@(SR,$r15), $r0	! get status register
+	mov	#SR, $r0
+	mov.l	@($r0,$r15), $r0	! get status register
 	shll	$r0
 	shll	$r0		! kernel space?
 	bt	restore_all	! Yes, it's from kernel, go back soon
 	!
-	RESTORE_FLAGS()
-9:	bra	ret_with_reschedule
+	STI()
+	bra	ret_with_reschedule
 	 nop
 
 ENTRY(ret_from_exception)
-	mov.l	@(SR,$r15), $r0	! get status register
+	mov	#SR, $r0
+	mov.l	@($r0,$r15), $r0	! get status register
 	shll	$r0
 	shll	$r0		! kernel space?
 	bt	restore_all	! Yes, it's from kernel, go back soon
 	!
-	RESTORE_FLAGS()
-9:	bra	ret_from_syscall
+	STI()
+	bra	ret_from_syscall
 	 nop
 	.balign	4
 __INV_IMASK:
@@ -351,7 +407,9 @@
 
 	.balign 4
 syscall_ret:
+#ifdef COMPAT_OLD_SYSCALL_ABI
 	add	$r8, $r15	! pop off the arguments
+#endif
 	mov.l	$r0, @(R0,$r15)	! save the return value
 	/* fall through */
 
@@ -366,9 +424,7 @@
 	jsr	@$r0
 	 nop
 ret_with_reschedule:
-	stc	$ksp, $r1
-	mov.l	__minus8192, $r0
-	add	$r0, $r1
+	stc	$k_current, $r1
 	mov.l	@(need_resched,$r1), $r0
 	tst	#0xff, $r0
 	bf	reschedule
@@ -389,30 +445,14 @@
 	.long	SYMBOL_NAME(softirq_state)
 __do_softirq:
 	.long	SYMBOL_NAME(do_softirq)
-__minus8192:
-	.long	-8192		! offset from stackbase to tsk
 
 	.balign 4
 restore_all:
 #if defined(__SH4__)
-	mov.l	__fpu_prepare_fd, $r1
-	jsr	@$r1
+	mov.l	__fpu_prepare_fd, $r0
+	jsr	@$r0
 	 stc	$sr, $r4
 #endif
-	add	#4, $r15	! Skip syscall number
-	mov.l	@$r15+, $r11	! Got SSR into R11
-#if defined(__SH4__)
-	mov	$r11, $r12
-#endif
-	!
-	mov.l	1f, $r1
-	stc	$sr, $r0
-	and	$r1, $r0	! Get FD
-	mov.l	2f, $r1
-	and	$r1, $r11
-	or	$r0, $r11	! Inherit the FD value of SR
-	stc	$r5_bank, $r0
-	or	$r0, $r11	! Inherit the IMASK value
 	!
 	mov.l	@$r15+, $r0
 	mov.l	@$r15+, $r1
@@ -422,14 +462,12 @@
 	mov.l	@$r15+, $r5
 	mov.l	@$r15+, $r6
 	mov.l	@$r15+, $r7
-	stc	$sr, $r14
+	!
+	stc	$sr, $r8
 	mov.l	__blrb_flags, $r9	! BL =1, RB=1
-	or	$r9, $r14
-	ldc	$r14, $sr		! here, change the register bank
-	mov	$r11, $k1
-#if defined(__SH4__)
-	mov	$r12, $k2
-#endif
+	or	$r9, $r8
+	ldc	$r8, $sr		! here, change the register bank
+	!
 	mov.l	@$r15+, $r8
 	mov.l	@$r15+, $r9
 	mov.l	@$r15+, $r10
@@ -437,20 +475,33 @@
 	mov.l	@$r15+, $r12
 	mov.l	@$r15+, $r13
 	mov.l	@$r15+, $r14
-	mov.l	@$r15+, $k0	! original stack
+	mov.l	@$r15+, $k4	! original stack pointer
+	ldc.l	@$r15+, $spc
+	lds.l	@$r15+, $pr
+	mov.l	@$r15+, $k3	! original SR
 	ldc.l	@$r15+, $gbr
 	lds.l	@$r15+, $mach
 	lds.l	@$r15+, $macl
-	lds.l	@$r15+, $pr
-	ldc.l	@$r15+, $spc
-	ldc	$k1, $ssr
+	add	#4, $r15	! Skip syscall number
+	!
+	! Calculate new SR value
+	mov	$k3, $k2	! original SR value
+	mov.l	1f, $k1
+	stc	$sr, $k0
+	and	$k1, $k0	! Get current FD-bit
+	mov.l	2f, $k1
+	and	$k1, $k2	! Mask orignal SR value
+	or	$k0, $k2	! Inherit current FD-bit
+	or	$g_imask, $k2	! Inherit the IMASK-bits
+	ldc	$k2, $ssr
+	!
 #if defined(__SH4__)
-	shll	$k1
-	shll	$k1
+	shll	$k2
+	shll	$k2
 	bf	9f		! user mode
 	/* Kernel to kernel transition */
 	mov.l	1f, $k1
-	tst	$k1, $k2
+	tst	$k1, $k3
 	bf	9f		! it hadn't FPU
 	! Kernel to kernel and FPU was used
 	! There's the case we don't get FPU now
@@ -462,14 +513,15 @@
 	ldc	$k2, $sr		! Grab FPU
 	mov.l	__init_task_flags, $k1
 	mov.l	@$k1, $k2
-	mov.l	__PF_USEDFPU, $k1
-	or	$k1, $k2
-	mov.l	__init_task_flags, $k1
+	mov.l	__PF_USEDFPU, $k0
+	or	$k0, $k2
 	mov.l	$k2, @$k1		! Set init_task.flags |= PF_USEDFPU
 	!
 	! Restoring FPU...
 	!
-7:	fmov.s	@$r15+, $fr0
+7:	mov.l	3f, $k1
+	lds	$k1, $fpscr
+	fmov.s	@$r15+, $fr0
 	fmov.s	@$r15+, $fr1
 	fmov.s	@$r15+, $fr2
 	fmov.s	@$r15+, $fr3
@@ -489,7 +541,7 @@
 	lds.l	@$r15+, $fpul
 9:
 #endif
-	mov	$k0, $r15
+	mov	$k4, $r15
 	rte
 	 nop
 
@@ -505,6 +557,7 @@
 #endif
 1:	.long	0x00008000	! FD
 2:	.long	0xffff7f0f	! ~(IMASK+FD)
+3:	.long	0x00080000	! SZ=0, PR=1
 
 ! Exception Vector Base
 !
@@ -569,6 +622,9 @@
 	! /* Currently it's not the case for GCC (only udivsi3_i4, divsi3_i4) */
 	sts.l	$fpul,  @-$r15
 	sts.l	$fpscr, @-$r15
+	mov.l	6f, $k1
+	lds	$k1, $fpscr
+	mov.l	3f, $k1
 	fmov.s	$fr15, @-$r15
 	fmov.s	$fr14, @-$r15
 	fmov.s	$fr13, @-$r15
@@ -584,40 +640,47 @@
 	fmov.s	$fr3, @-$r15
 	fmov.s	$fr2, @-$r15
 	fmov.s	$fr1, @-$r15
-	fmov.s	$fr0, @-$r15
 	bra 9f
-	 mov.l	3f, $k1
+	 fmov.s	$fr0, @-$r15
 #else
 	mov.l	3f, $k1
 	bt/s	9f		! it's from kernel to kernel transition
 	 mov	$r15, $k0	! save original stack to k0 anyway
 #endif
 8:	/* User space to kernel */
-	mov	$kernel_sp, $r15	! change to kernel stack
-	mov.l	4f, $k1			! let kernel release FPU
-9:	stc.l	$spc, @-$r15
-	sts.l	$pr, @-$r15
+	mov	#0x20, $k1
+	shll8	$k1			! $k1 <= 8192
+	add	$current, $k1
+	mov	$k1, $r15		! change to kernel stack
 	!
-	lds	$k3, $pr		! Set the return address to pr
+	mov.l	4f, $k1			! let kernel release FPU
+9:	mov	#-1, $k4
+	mov.l	$k4, @-$r15		! syscall_nr (default: -1)
 	!
 	sts.l	$macl, @-$r15
 	sts.l	$mach, @-$r15
 	stc.l	$gbr, @-$r15
-	mov.l	$k0, @-$r15	! save orignal stack
-	mov.l	$r14, @-$r15
+	stc.l	$ssr, @-$r15
+	sts.l	$pr, @-$r15
+	stc.l	$spc, @-$r15
 	!
-	stc	$sr, $r14	! Back to normal register bank, and
-	or	$k1, $r14	! Block all interrupts, may release FPU
-	mov.l	5f, $k1
-	and	$k1, $r14	! ...
-	ldc	$r14, $sr	! ...changed here.
+	lds	$k3, $pr		! Set the return address to pr
 	!
+	mov.l	$k0, @-$r15	! save orignal stack
+	mov.l	$r14, @-$r15
 	mov.l	$r13, @-$r15
 	mov.l	$r12, @-$r15
 	mov.l	$r11, @-$r15
 	mov.l	$r10, @-$r15
 	mov.l	$r9, @-$r15
 	mov.l	$r8, @-$r15
+	!
+	stc	$sr, $r8	! Back to normal register bank, and
+	or	$k1, $r8	! Block all interrupts, may release FPU
+	mov.l	5f, $k1
+	and	$k1, $r8	! ...
+	ldc	$r8, $sr	! ...changed here.
+	!
 	mov.l	$r7, @-$r15
 	mov.l	$r6, @-$r15
 	mov.l	$r5, @-$r15
@@ -626,23 +689,22 @@
 	mov.l	$r2, @-$r15
 	mov.l	$r1, @-$r15
 	mov.l	$r0, @-$r15
-	stc.l	$ssr, @-$r15
-	mov.l	$r0, @-$r15	! push $r0 again (for syscall number)
-	! Then, dispatch to the handler, according to the excepiton code.
-	stc	$k_ex_code, $r1
-	shlr2	$r1
-	shlr	$r1
-	mov.l	1f, $r0
-	add	$r1, $r0
-	mov.l	@$r0, $r0
-	jmp	@$r0
-	 mov.l	@$r15, $r0	! recovering $r0..
+	! Then, dispatch to the handler, according to the exception code.
+	stc	$k_ex_code, $r8
+	shlr2	$r8
+	shlr	$r8
+	mov.l	1f, $r9
+	add	$r8, $r9
+	mov.l	@$r9, $r9
+	jmp	@$r9
+	 nop
 	.balign	4
 1:	.long	SYMBOL_NAME(exception_handling_table)
 2:	.long	0x00008000	! FD=1
 3:	.long	0x000000f0	! FD=0, IMASK=15
 4:	.long	0x000080f0	! FD=1, IMASK=15
 5:	.long	0xcfffffff	! RB=0, BL=0
+6:	.long	0x00080000	! SZ=0, PR=1
 
 none:
 	rts
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/fpu.c linux/arch/sh/kernel/fpu.c
--- v2.3.99-pre5/linux/arch/sh/kernel/fpu.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/fpu.c	Mon Apr 24 13:54:17 2000
@@ -23,6 +23,7 @@
 {
 	asm volatile("sts.l	$fpul, @-%0\n\t"
 		     "sts.l	$fpscr, @-%0\n\t"
+		     "lds	%1, $fpscr\n\t"
 		     "frchg\n\t"
 		     "fmov.s	$fr15, @-%0\n\t"
 		     "fmov.s	$fr14, @-%0\n\t"
@@ -58,7 +59,8 @@
 		     "fmov.s	$fr1, @-%0\n\t"
 		     "fmov.s	$fr0, @-%0"
 		     : /* no output */
-		     : "r" ((char *)(&tsk->thread.fpu.hard.status))
+		     : "r" ((char *)(&tsk->thread.fpu.hard.status)),
+		       "r" (FPSCR_INIT)
 		     : "memory");
 
 	tsk->flags &= ~PF_USEDFPU;
@@ -68,7 +70,8 @@
 static void
 restore_fpu(struct task_struct *tsk)
 {
-	asm volatile("fmov.s	@%0+, $fr0\n\t"
+	asm volatile("lds	%1, $fpscr\n\t"
+		     "fmov.s	@%0+, $fr0\n\t"
 		     "fmov.s	@%0+, $fr1\n\t"
 		     "fmov.s	@%0+, $fr2\n\t"
 		     "fmov.s	@%0+, $fr3\n\t"
@@ -105,7 +108,7 @@
 		     "lds.l	@%0+, $fpscr\n\t"
 		     "lds.l	@%0+, $fpul\n\t"
 		     : /* no output */
-		     : "r" (&tsk->thread.fpu)
+		     : "r" (&tsk->thread.fpu), "r" (FPSCR_INIT)
 		     : "memory");
 }
 
@@ -163,7 +166,6 @@
 {
 	struct task_struct *tsk = current;
 
-	regs.syscall_nr = -1;
 	regs.pc += 2;
 
 	grab_fpu();
@@ -179,15 +181,34 @@
 {
 	struct task_struct *tsk = current;
 
-	regs.syscall_nr = -1;
-
 	if (!user_mode(&regs)) {
 		if (tsk != &init_task) {
 			unlazy_fpu(tsk);
 		}
 		tsk = &init_task;
-		if (tsk->flags & PF_USEDFPU)
-			BUG();
+		if (tsk->flags & PF_USEDFPU) {
+			/*
+			 * This weird situation can be occurred.
+			 *
+			 * There's race condition in __cli:
+			 *
+			 *   (1) $SR --> register
+			 *   (2) Set IMASK of register
+			 *   (3) $SR <-- register
+			 *
+			 * Between (1) and (2), or (2) and (3) getting
+			 * interrupt, and interrupt handler (or
+			 * softirq) may use FPU.
+			 *
+			 * Then, SR.FD is overwritten by (3).
+			 *
+			 * This results init_task.PF_USEDFPU is on,
+			 * with SR.FD == 1.
+			 *
+			 */
+			release_fpu();
+			return;
+		}
 	}
 
 	grab_fpu();
@@ -216,8 +237,8 @@
 			grab_fpu();
 		else {
 			if (!(sr & SR_FD)) {
-				release_fpu();
 				BUG();
+				release_fpu();
 			}
 		}
 		return;
@@ -228,16 +249,20 @@
 			grab_fpu();
 		else {
 			if (init_task.flags & PF_USEDFPU) {
-				init_task.flags &= ~PF_USEDFPU;
-				BUG();
+				/*
+				 * This weird situation can be occurred.
+				 * See the comment in do_fpu_state_restore.
+				 */
+				grab_fpu();
+				save_fpu(&init_task);
 			}
 		}
 	} else {
 		if (init_task.flags & PF_USEDFPU)
 			save_fpu(&init_task);
 		else {
-			release_fpu();
 			BUG();
+			release_fpu();
 		}
 	}
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S
--- v2.3.99-pre5/linux/arch/sh/kernel/head.S	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/head.S	Mon Apr 24 13:54:17 2000
@@ -41,12 +41,21 @@
 	ldc	$r0, $sr
 	!			Initialize global interrupt mask
 	mov	#0, $r0
-	ldc	$r0, $r5_bank
+	ldc	$r0, $r6_bank
 	!
 	mov.l	2f, $r0
 	mov	$r0, $r15	! Set initial r15 (stack pointer)
-	ldc	$r0, $r4_bank	!   and stack base
+	mov	#0x20, $r1	!
+	shll8	$r1		! $r1 = 8192
+	sub	$r1, $r0	!
+	ldc	$r0, $r7_bank	! ... and init_task
 	!
+#if defined(__SH4__)
+	!                       Initialize fpu
+	mov.l   7f, $r0
+	jsr     @$r0
+	 nop
+#endif
 	!			Enable cache
 	mov.l	6f, $r0
 	jsr	@$r0
@@ -71,3 +80,6 @@
 4:	.long	SYMBOL_NAME(_end)
 5:	.long	SYMBOL_NAME(start_kernel)
 6:	.long	SYMBOL_NAME(cache_init)
+#if defined(__SH4__)
+7:	.long   SYMBOL_NAME(fpu_init)
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c
--- v2.3.99-pre5/linux/arch/sh/kernel/irq.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/irq.c	Mon Apr 24 13:54:17 2000
@@ -235,8 +235,6 @@
 	struct irqaction * action;
 	unsigned int status;
 
-	regs.syscall_nr = -1;	/* It's not system call */
-
 	/* Get IRQ number */
 	asm volatile("stc	$r2_bank, %0\n\t"
 		     "shlr2	%0\n\t"
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/irq_imask.c linux/arch/sh/kernel/irq_imask.c
--- v2.3.99-pre5/linux/arch/sh/kernel/irq_imask.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/irq_imask.c	Mon Apr 24 13:54:17 2000
@@ -43,7 +43,7 @@
 }
 
 static struct hw_interrupt_type imask_irq_type = {
-	"Interrupt using IMASK of SR register",
+	"SR.IMASK",
 	startup_imask_irq,
 	shutdown_imask_irq,
 	enable_imask_irq,
@@ -56,13 +56,13 @@
 {
 	unsigned long __dummy;
 
-	asm volatile("ldc	%2, $r5_bank\n\t"
+	asm volatile("ldc	%2, $r6_bank\n\t"
 		     "stc	$sr, %0\n\t"
 		     "and	#0xf0, %0\n\t"
-		     "shlr8	%0\n\t"
-		     "cmp/eq	#0x0f, %0\n\t"
-		     "bt	1f	! CLI-ed\n\t"
-		     "stc	$sr, %0\n\t"
+		     "shlr2	%0\n\t"
+		     "cmp/eq	#0x3c, %0\n\t"
+		     "bt/s	1f	! CLI-ed\n\t"
+		     " stc	$sr, %0\n\t"
 		     "and	%1, %0\n\t"
 		     "or	%2, %0\n\t"
 		     "ldc	%0, $sr\n"
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c
--- v2.3.99-pre5/linux/arch/sh/kernel/irq_onchip.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/irq_onchip.c	Mon Apr 24 13:54:17 2000
@@ -61,7 +61,7 @@
 }
 
 static struct hw_interrupt_type onChip_irq_type = {
-	"On-Chip Supporting Module",
+	"On-Chip-IPR",
 	startup_onChip_irq,
 	shutdown_onChip_irq,
 	enable_onChip_irq,
@@ -193,7 +193,7 @@
 }
 
 static struct hw_interrupt_type onChip2_irq_type = {
-	"SH7709 Extended On-Chip Supporting Module",
+	"Extended-IPR",
 	startup_onChip2_irq,
 	shutdown_onChip2_irq,
 	enable_onChip2_irq,
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.3.99-pre5/linux/arch/sh/kernel/process.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/process.c	Mon Apr 24 13:54:17 2000
@@ -136,20 +136,20 @@
  */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
-	register unsigned long __sc0 __asm__ ("$r0") = __NR_clone;
+	register unsigned long __sc0 __asm__ ("$r3") = __NR_clone;
 	register unsigned long __sc4 __asm__ ("$r4") = (long) flags | CLONE_VM;
 	register unsigned long __sc5 __asm__ ("$r5") = 0;
 	register unsigned long __sc8 __asm__ ("$r8") = (long) arg;
 	register unsigned long __sc9 __asm__ ("$r9") = (long) fn;
 
-	__asm__("trapa	#0\n\t" 	/* Linux/SH system call */
+	__asm__("trapa	#0x12\n\t" 	/* Linux/SH system call */
 		"tst	#0xff, $r0\n\t"	/* child or parent? */
 		"bf	1f\n\t"		/* parent - jump */
 		"jsr	@$r9\n\t"	/* call fn */
 		" mov	$r8, $r4\n\t"	/* push argument */
 		"mov	$r0, $r4\n\t"	/* return value to arg of exit */
-		"mov	%2, $r0\n\t"	/* exit */
-		"trapa	#0\n"
+		"mov	%2, $r3\n\t"	/* exit */
+		"trapa	#0x11\n"
 		"1:"
 		: "=z" (__sc0)
 		: "0" (__sc0), "i" (__NR_exit),
@@ -194,7 +194,11 @@
 
 	fpvalid = tsk->used_math;
 	if (fpvalid) {
+		unsigned long flags;
+
+		save_and_cli(flags);
 		unlazy_fpu(tsk);
+		restore_flags(flags);
 		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
 	}
 
@@ -214,7 +218,11 @@
 	struct task_struct *tsk = current;
 
 	if (tsk != &init_task) {
+		unsigned long flags;
+
+		save_and_cli(flags);
 		unlazy_fpu(tsk);
+		restore_flags(flags);
 		p->thread.fpu = current->thread.fpu;
 		p->used_math = tsk->used_math;
 	}
@@ -263,16 +271,21 @@
 void __switch_to(struct task_struct *prev, struct task_struct *next)
 {
 #if defined(__SH4__)
-	if (prev != &init_task)
+	if (prev != &init_task) {
+		unsigned long flags;
+
+		save_and_cli(flags);
 		unlazy_fpu(prev);
+		restore_flags(flags);
+	}
 #endif
 	/*
-	 * Restore the kernel stack onto kernel mode register
-	 *   	k4 (r4_bank1)
+	 * Restore the kernel mode register
+	 *   	k7 (r7_bank1)
 	 */
-	asm volatile("ldc	%0, $r4_bank"
+	asm volatile("ldc	%0, $r7_bank"
 		     : /* no output */
-		     :"r" ((unsigned long)next+8192));
+		     :"r" (next));
 }
 
 asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c
--- v2.3.99-pre5/linux/arch/sh/kernel/setup.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/setup.c	Mon Apr 24 13:54:17 2000
@@ -244,7 +244,7 @@
 
 	/*
 	 * Reserve the kernel text and
-	 * Reserve the bootmem bitmap.We do this in two steps (first step
+	 * Reserve the bootmem bitmap. We do this in two steps (first step
 	 * was init_bootmem()), because this catches the (definitely buggy)
 	 * case of us accidentally initializing the bootmem allocator with
 	 * an invalid RAM area.
@@ -262,17 +262,17 @@
 	if (LOADER_TYPE && INITRD_START) {
 		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
 			reserve_bootmem(INITRD_START+__MEMORY_START, INITRD_SIZE);
- 			initrd_start =
- 				INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0;
+			initrd_start =
+				INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0;
 			initrd_end = initrd_start + INITRD_SIZE;
 		} else {
- 			printk("initrd extends beyond end of memory "
- 			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			printk("initrd extends beyond end of memory "
+			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
 				    INITRD_START + INITRD_SIZE,
 				    max_low_pfn << PAGE_SHIFT);
- 			initrd_start = 0;
- 		}
- 	}
+			initrd_start = 0;
+		}
+	}
 #endif
 
 #if 0
@@ -301,10 +301,9 @@
 #endif
 
 #if defined(__SH4__)
+	/* We already grab/initialized FPU in head.S.  Make it consisitent. */
 	init_task.used_math = 1;
 	init_task.flags |= PF_USEDFPU;
-	grab_fpu();
-	fpu_init();
 #endif
 	paging_init();
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c
--- v2.3.99-pre5/linux/arch/sh/kernel/signal.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/kernel/signal.c	Mon Apr 24 13:54:17 2000
@@ -152,30 +152,36 @@
 #if defined(__SH4__)
 static inline int restore_sigcontext_fpu(struct sigcontext *sc)
 {
-	current->used_math = 1;
+	struct task_struct *tsk = current;
+
+	tsk->used_math = 1;
 	return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
-				sizeof(long)*(NUM_FPU_REGS*2+2));
+				sizeof(long)*(16*2+2));
 }
 
 static inline int save_sigcontext_fpu(struct sigcontext *sc)
 {
 	struct task_struct *tsk = current;
+	unsigned long flags;
 
 	if (!tsk->used_math) {
-		sc->owend_fp = 0;
+		sc->sc_ownedfp = 0;
 		return 0;
 	}
 
-	sc->owend_fp = 1;
+	sc->sc_ownedfp = 1;
 
 	/* This will cause a "finit" to be triggered by the next
 	   attempted FPU operation by the 'current' process.
 	   */
 	tsk->used_math = 0;
 
+	save_and_cli(flags);
 	unlazy_fpu(tsk);
+	restore_flags(flags);
+
 	return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
-			      sizeof(long)*(NUM_FPU_REGS*2+2));
+			      sizeof(long)*(16*2+2));
 }
 #endif
 
@@ -206,7 +212,7 @@
 		regs->sr |= SR_FD; /* Release FPU */
 		clear_fpu(tsk);
 		current->used_math = 0;
-		__get_user (owned_fp, &context->sc_ownedfp);
+		__get_user (owned_fp, &sc->sc_ownedfp);
 		if (owned_fp)
 			err |= restore_sigcontext_fpu(sc);
 	}
@@ -363,11 +369,11 @@
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		regs->pr = (unsigned long) ka->sa.sa_restorer;
 	} else {
-		/* This is : mov  #__NR_sigreturn,r0 ; trapa #0 */
+		/* This is : mov  #__NR_sigreturn,r3 ; trapa #0x10 */
 #ifdef __LITTLE_ENDIAN__
-		unsigned long code = 0xc300e000 | (__NR_sigreturn);
+		unsigned long code = 0xc310e300 | (__NR_sigreturn);
 #else
-		unsigned long code = 0xe000c300 | (__NR_sigreturn << 16);
+		unsigned long code = 0xe300c310 | (__NR_sigreturn << 16);
 #endif
 
 		regs->pr = (unsigned long) frame->retcode;
@@ -437,11 +443,11 @@
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		regs->pr = (unsigned long) ka->sa.sa_restorer;
 	} else {
-		/* This is : mov  #__NR_rt_sigreturn,r0 ; trapa #0 */
+		/* This is : mov  #__NR_rt_sigreturn,r3 ; trapa #0x10 */
 #ifdef __LITTLE_ENDIAN__
-		unsigned long code = 0xc300e000 | (__NR_rt_sigreturn);
+		unsigned long code = 0xc310e300 | (__NR_rt_sigreturn);
 #else
-		unsigned long code = 0xe000c300 | (__NR_rt_sigreturn << 16);
+		unsigned long code = 0xe300c310 | (__NR_rt_sigreturn << 16);
 #endif
 
 		regs->pr = (unsigned long) frame->retcode;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c
--- v2.3.99-pre5/linux/arch/sh/kernel/time.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/time.c	Mon Apr 24 13:54:17 2000
@@ -33,6 +33,23 @@
 #define TMU0_TCR_INIT	0x0020
 #define TMU_TSTR_INIT	1
 
+/* RCR1 Bits */
+#define RCR1_CF		0x80	/* Carry Flag             */
+#define RCR1_CIE	0x10	/* Carry Interrupt Enable */
+#define RCR1_AIE	0x08	/* Alarm Interrupt Enable */
+#define RCR1_AF		0x01	/* Alarm Flag             */
+
+/* RCR2 Bits */
+#define RCR2_PEF	0x80	/* PEriodic interrupt Flag */
+#define RCR2_PESMASK	0x70	/* Periodic interrupt Set  */
+#define RCR2_RTCEN	0x08	/* ENable RTC              */
+#define RCR2_ADJ	0x04	/* ADJustment (30-second)  */
+#define RCR2_RESET	0x02	/* Reset bit               */
+#define RCR2_START	0x01	/* Start bit               */
+
+#define RTC_IRQ		22
+#define RTC_IPR_OFFSET	0
+
 #if defined(__sh3__)
 #define TMU_TOCR	0xfffffe90	/* Byte access */
 #define TMU_TSTR	0xfffffe92	/* Byte access */
@@ -43,9 +60,6 @@
 
 #define FRQCR		0xffffff80
 
-#define RTC_IRQ         22
-#define RTC_IPR_OFFSET  0
-
 /* SH-3 RTC */
 #define R64CNT  	0xfffffec0
 #define RSECCNT 	0xfffffec2
@@ -74,9 +88,6 @@
 
 #define FRQCR		0xffc00000
 
-#define RTC_IRQ		22
-#define RTC_IPR_OFFSET	0
-
 /* SH-4 RTC */
 #define R64CNT  	0xffc80000
 #define RSECCNT 	0xffc80004
@@ -149,7 +160,7 @@
 	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
 
-	ctrl_outb(0x02, RCR2);  /* reset pre-scaler & stop RTC */
+	ctrl_outb(RCR2_RESET, RCR2);  /* Reset pre-scaler & stop RTC */
 
 	cmos_minutes = ctrl_inb(RMINCNT);
 	BCD_TO_BIN(cmos_minutes);
@@ -178,7 +189,7 @@
 		retval = -1;
 	}
 
-	ctrl_outb(0x01, RCR2);  /* start RTC */
+	ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start RTC */
 
 	return retval;
 }
@@ -283,8 +294,8 @@
 	unsigned int sec, min, hr, wk, day, mon, yr, yr100;
 
  again:
-	ctrl_outb(0x01, RCR1);  /* clear CF bit */
 	do {
+		ctrl_outb(0, RCR1);  /* Clear CF-bit */
 		sec = ctrl_inb(RSECCNT);
 		min = ctrl_inb(RMINCNT);
 		hr  = ctrl_inb(RHRCNT);
@@ -299,7 +310,7 @@
 		yr  = ctrl_inb(RYRCNT);
 		yr100 = (yr == 0x99) ? 0x19 : 0x20;
 #endif
-	} while ((ctrl_inb(RCR1) & 0x80) != 0);
+	} while ((ctrl_inb(RCR1) & RCR1_CF) != 0);
 
 	BCD_TO_BIN(yr100);
 	BCD_TO_BIN(yr);
@@ -313,7 +324,7 @@
 	    hr > 23 || min > 59 || sec > 59) {
 		printk(KERN_ERR
 		       "SH RTC: invalid value, resetting to 1 Jan 2000\n");
-		ctrl_outb(0x02, RCR2);  /* reset, stop */
+		ctrl_outb(RCR2_RESET, RCR2);  /* Reset & Stop */
 		ctrl_outb(0, RSECCNT);
 		ctrl_outb(0, RMINCNT);
 		ctrl_outb(0, RHRCNT);
@@ -325,7 +336,7 @@
 #else
 		ctrl_outb(0, RYRCNT);
 #endif
-		ctrl_outb(0x01, RCR2);  /* start */
+		ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start */
 		goto again;
 	}
 
@@ -339,13 +350,13 @@
 
 	sti();
 	do {} while (ctrl_inb(R64CNT) != 0);
-	ctrl_outb(0x11, RCR1);
+	ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */
 	asm volatile(
 		"1:\t"
 		"tst	%1,%1\n\t"
 		"bt/s	1b\n\t"
 		" add	#1,%0"
-		: "=&r"(count), "=&z" (__dummy)
+		: "=r"(count), "=z" (__dummy)
 		: "0" (0), "1" (0));
 	cli();
 	/*
@@ -373,7 +384,7 @@
 
 static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	ctrl_outb(0x01, RCR1);
+	ctrl_outb(0, RCR1);	/* Disable Carry Interrupts */
 	regs->regs[0] = 1;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c
--- v2.3.99-pre5/linux/arch/sh/kernel/traps.c	Tue Mar  7 14:32:25 2000
+++ linux/arch/sh/kernel/traps.c	Mon Apr 24 13:54:17 2000
@@ -43,7 +43,6 @@
  \
 	asm volatile("stc	$r2_bank, %0": "=r" (error_code)); \
 	sti(); \
-	regs.syscall_nr = -1; \
 	tsk->thread.error_code = error_code; \
 	tsk->thread.trap_no = trapnr; \
 	force_sig(signr, tsk); \
@@ -95,9 +94,9 @@
 DO_ERROR(12, SIGILL,  "reserved instruction", reserved_inst, current)
 DO_ERROR(13, SIGILL,  "illegal slot instruction", illegal_slot_inst, current)
 
-asmlinkage void do_exception_error (unsigned long r4, unsigned long r5,
-				    unsigned long r6, unsigned long r7,
-				    struct pt_regs regs)
+asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
+				   unsigned long r6, unsigned long r7,
+				   struct pt_regs regs)
 {
 	long ex;
 	asm volatile("stc	$r2_bank, %0" : "=r" (ex));
@@ -131,7 +130,8 @@
 	unsigned long *p;
 
 	asm("mov	$r15, %0" : "=r" (start));
-	asm("stc	$r4_bank, %0" : "=r" (end));
+	asm("stc	$r7_bank, %0" : "=r" (end));
+	end += 8192;
 
 	printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end);
 	for (p=start; p < end; p++)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c
--- v2.3.99-pre5/linux/arch/sh/mm/cache.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/mm/cache.c	Mon Apr 24 13:54:17 2000
@@ -175,13 +175,13 @@
  *
  * For SH-4, flush (write back) Operand Cache, as Instruction Cache
  * doesn't have "updated" data.
+ *
+ * Assumes that called in interrupt disabled.
  */
 static void cache_wback_all(void)
 {
-	unsigned long flags;
 	unsigned long addr, data, i, j;
 
-	save_and_cli(flags);
 	jump_to_P2();
 
 	for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
@@ -197,7 +197,6 @@
 	}
 
 	back_to_P1();
-	restore_flags(flags);
 }
 
 static void
@@ -314,11 +313,11 @@
 {
 	unsigned long flags;
 
+	save_and_cli(flags);
 	/* Write back Operand Cache */
-	cache_wback_all ();
+	cache_wback_all();
 
 	/* Then, invalidate Instruction Cache and Operand Cache */
-	save_and_cli(flags);
 	jump_to_P2();
 	ctrl_outl(CCR_CACHE_INIT, CCR);
 	back_to_P1();
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.3.99-pre5/linux/arch/sh/mm/fault.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sh/mm/fault.c	Mon Apr 24 15:52:10 2000
@@ -55,7 +55,7 @@
 	start &= PAGE_MASK;
 
 	for (;;) {
-		if (handle_mm_fault(current, vma, start, 1) <= 0)
+		if (handle_mm_fault(current->mm, vma, start, 1) <= 0)
 			goto bad_area;
 		if (!size)
 			break;
@@ -168,7 +168,7 @@
 	 * the fault.
 	 */
 	{
-		int fault = handle_mm_fault(tsk, vma, address, writeaccess);
+		int fault = handle_mm_fault(mm, vma, address, writeaccess);
 		if (fault < 0)
 			goto out_of_memory;
 		if (!fault)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v2.3.99-pre5/linux/arch/sparc/kernel/Makefile	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/kernel/Makefile	Wed Apr 12 09:12:34 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.52 1999/12/21 04:02:17 davem Exp $
+# $Id: Makefile,v 1.53 2000/03/31 04:06:19 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/cpu.c linux/arch/sparc/kernel/cpu.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/cpu.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/cpu.c	Wed Apr 12 09:12:34 2000
@@ -92,7 +92,7 @@
   /* Someone please write the code to support this beast! ;) */
   { 2, 0, "Bipolar Integrated Technology - B5010"},
   { 3, 0, "LSI Logic Corporation - unknown-type"},
-  { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"},
+  { 4, 0, "Texas Instruments, Inc. - SuperSparc-(II)"},
   /* SparcClassic  --  borned STP1010TAB-50*/
   { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
   { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/ptrace.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/ptrace.c	Wed Apr 12 09:16:31 2000
@@ -60,7 +60,7 @@
 static void
 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
 {
-	if (current->personality & PER_BSD)
+	if (current->personality == PER_SUNOS)
 		pt_succ_return (regs, val);
 	else
 		pt_succ_return_linux (regs, val, addr);
@@ -155,7 +155,7 @@
 		pt_error_return(regs, EIO);
 		return;
 	}
-	if (current->personality & PER_BSD)
+	if (current->personality == PER_SUNOS)
 		pt_succ_return (regs, v);
 	else
 		pt_succ_return_linux (regs, v, addr);
@@ -310,8 +310,8 @@
 		goto out;
 	}
 
-	if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH))
-	    || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) {
+	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
+	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
 		unsigned long flags;
 
 		if(child == current) {
@@ -349,9 +349,7 @@
 		pt_succ_return(regs, 0);
 		goto out;
 	}
-	if (!(child->flags & PF_PTRACED)
-	    && ((current->personality & PER_BSD) && (request != PTRACE_SUNATTACH))
-	    && (!(current->personality & PER_BSD) && (request != PTRACE_ATTACH))) {
+	if (!(child->flags & PF_PTRACED)) {
 		pt_error_return(regs, ESRCH);
 		goto out;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/signal.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/kernel/signal.c	Wed Apr 12 09:12:34 2000
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.101 2000/01/21 11:38:38 jj Exp $
+/*  $Id: signal.c,v 1.102 2000/04/08 02:11:36 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/sun4d_smp.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/sun4d_smp.c	Fri Apr 21 16:37:39 2000
@@ -8,7 +8,6 @@
 
 #include <asm/head.h>
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/threads.h>
@@ -443,38 +442,14 @@
 	panic("Bogon SMP message pass.");
 }
 
-/* Protects counters touched during level14 ticker */
-static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
-
-#ifdef CONFIG_PROFILE
-
-/* 32-bit Sparc specific profiling function. */
-static inline void sparc_do_profile(unsigned long pc)
-{
-	if(prof_buffer && current->pid) {
-		extern int _stext;
-
-		pc -= (unsigned long) &_stext;
-		pc >>= prof_shift;
-
-		spin_lock(&ticker_lock);
-		if(pc < prof_len)
-			prof_buffer[pc]++;
-		else
-			prof_buffer[prof_len - 1]++;
-		spin_unlock(&ticker_lock);
-	}
-}
-
-#endif
-
 extern unsigned int prof_multiplier[NR_CPUS];
 extern unsigned int prof_counter[NR_CPUS];
 
 extern void update_one_process(struct task_struct *p, unsigned long ticks,
 			       unsigned long user, unsigned long system,
 			       int cpu);
-			       
+
+extern void sparc_do_profile(unsigned long pc, unsigned long o7);
 
 void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
 {
@@ -493,12 +468,13 @@
 		show_leds(cpu);
 	}
 
-#ifdef CONFIG_PROFILE
 	if(!user_mode(regs))
-		sparc_do_profile(regs->pc);
-#endif
+		sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
+
 	if(!--prof_counter[cpu]) {
 		int user = user_mode(regs);
+
+		irq_enter(cpu, 0);
 		if(current->pid) {
 			update_one_process(current, 1, user, !user, cpu);
 
@@ -507,7 +483,6 @@
 				current->need_resched = 1;
 			}
 
-			spin_lock(&ticker_lock);
 			if(user) {
 				if(current->priority < DEF_PRIORITY) {
 					kstat.cpu_nice++;
@@ -520,9 +495,9 @@
 				kstat.cpu_system++;
 				kstat.per_cpu_system[cpu]++;
 			}
-			spin_unlock(&ticker_lock);
 		}
 		prof_counter[cpu] = prof_multiplier[cpu];
+		irq_exit(cpu, 0);
 	}
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/sun4m_smp.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/sun4m_smp.c	Fri Apr 14 09:37:09 2000
@@ -440,27 +440,6 @@
 	ccall_info.processors_out[i] = 1;
 }
 
-/* Protects counters touched during level14 ticker */
-static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
-
-/* 32-bit Sparc specific profiling function. */
-static inline void sparc_do_profile(unsigned long pc)
-{
-	if(prof_buffer && current->pid) {
-		extern int _stext;
-
-		pc -= (unsigned long) &_stext;
-		pc >>= prof_shift;
-
-		spin_lock(&ticker_lock);
-		if(pc < prof_len)
-			prof_buffer[pc]++;
-		else
-			prof_buffer[prof_len - 1]++;
-		spin_unlock(&ticker_lock);
-	}
-}
-
 extern unsigned int prof_multiplier[NR_CPUS];
 extern unsigned int prof_counter[NR_CPUS];
 
@@ -468,6 +447,8 @@
 			       unsigned long user, unsigned long system,
 			       int cpu);
 
+extern void sparc_do_profile(unsigned long pc, unsigned long o7);
+
 void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
@@ -475,7 +456,7 @@
 	clear_profile_irq(mid_xlate[cpu]);
 
 	if(!user_mode(regs))
-		sparc_do_profile(regs->pc);
+		sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
 
 	if(!--prof_counter[cpu]) {
 		int user = user_mode(regs);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sys_solaris.c linux/arch/sparc/kernel/sys_solaris.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/sys_solaris.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/kernel/sys_solaris.c	Thu Apr 13 08:11:48 2000
@@ -23,9 +23,7 @@
 	int ret;
 
 	lock_kernel();
-	put_exec_domain(current->exec_domain);
-	current->personality = PER_SVR4;
-	current->exec_domain = lookup_exec_domain(PER_SVR4);
+	set_personality(PER_SVR4);
 
 	if (current->exec_domain && current->exec_domain->handler){
 		current->exec_domain->handler (0, regs);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/sys_sunos.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Wed Apr 26 09:25:17 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.118 2000/03/26 11:28:56 davem Exp $
+/* $Id: sys_sunos.c,v 1.121 2000/04/13 00:55:48 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -50,6 +50,7 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/nfs.h>
+#include <linux/nfs2.h>
 #include <linux/nfs_mount.h>
 
 /* for sunos_select */
@@ -69,7 +70,6 @@
 
 	down(&current->mm->mmap_sem);
 	lock_kernel();
-	current->personality |= PER_BSD;
 	if(flags & MAP_NORESERVE) {
 		static int cnt;
 		if (cnt++ < 10)
@@ -170,7 +170,7 @@
 	 */
 	if (brk <= current->mm->brk) {
 		current->mm->brk = brk;
-		do_munmap(newbrk, oldbrk-newbrk);
+		do_munmap(current->mm, newbrk, oldbrk-newbrk);
 		goto out;
 	}
 	/*
@@ -582,7 +582,6 @@
 
 	/* SunOS binaries expect that select won't change the tvp contents */
 	lock_kernel();
-	current->personality |= STICKY_TIMEOUTS;
 	ret = sys_select (width, inp, outp, exp, tvp);
 	if (ret == -EINTR && tvp) {
 		time_t sec, usec;
@@ -712,7 +711,7 @@
 	 * address to create a socket and bind it to a reserved
 	 * port on this system
 	 */
-	if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))
+	if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount)))
 		return -EFAULT;
 
 	server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -803,14 +802,14 @@
 		dev_fname = getname(data);
 	} else if(strcmp(type_page, "nfs") == 0) {
 		ret = sunos_nfs_mount (dir_page, flags, data);
-		goto out2
+		goto out2;
         } else if(strcmp(type_page, "ufs") == 0) {
 		printk("Warning: UFS filesystem mounts unsupported.\n");
 		ret = -ENODEV;
-		goto out2
+		goto out2;
 	} else if(strcmp(type_page, "proc")) {
 		ret = -ENODEV;
-		goto out2
+		goto out2;
 	}
 	ret = PTR_ERR(dev_fname);
 	if (IS_ERR(dev_fname))
@@ -1054,18 +1053,6 @@
 	return rval;
 }
 
-asmlinkage int sunos_open(const char *filename, int flags, int mode)
-{
-	int ret;
-
-	lock_kernel();
-	current->personality |= PER_BSD;
-	ret = sys_open (filename, flags, mode);
-	unlock_kernel();
-	return ret;
-}
-
-
 #define SUNOS_EWOULDBLOCK 35
 
 /* see the sunos man page read(2v) for an explanation
@@ -1199,8 +1186,6 @@
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
-
-	current->personality |= PER_BSD;
 
 	if(act) {
 		old_sigset_t mask;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.3.99-pre5/linux/arch/sparc/kernel/systbls.S	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc/kernel/systbls.S	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.96 2000/03/15 02:43:32 davem Exp $
+/* $Id: systbls.S,v 1.97 2000/04/13 00:55:49 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -79,7 +79,7 @@
 	.globl sunos_sys_table
 sunos_sys_table:
 /*0*/	.long sunos_indir, sys_exit, sys_fork
-	.long sunos_read, sunos_write, sunos_open
+	.long sunos_read, sunos_write, sys_open
 	.long sys_close, sunos_wait4, sys_creat
 	.long sys_link, sys_unlink, sunos_execv
 	.long sys_chdir, sunos_nosys, sys_mknod
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v2.3.99-pre5/linux/arch/sparc/kernel/time.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/sparc/kernel/time.c	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.53 2000/02/09 21:11:04 davem Exp $
+/* $Id: time.c,v 1.54 2000/04/13 08:14:30 anton Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -70,6 +70,37 @@
 
 #endif
 
+static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+
+/* 32-bit Sparc specific profiling function. */
+void sparc_do_profile(unsigned long pc, unsigned long o7)
+{
+	if(prof_buffer && current->pid) {
+		extern int _stext;
+		extern int __copy_user_begin, __copy_user_end;
+		extern int __atomic_begin, __atomic_end;
+		extern int __bitops_begin, __bitops_end;
+
+		if ((pc >= (unsigned long) &__copy_user_begin &&
+		     pc < (unsigned long) &__copy_user_end) ||
+		    (pc >= (unsigned long) &__atomic_begin &&
+		     pc < (unsigned long) &__atomic_end) ||
+		    (pc >= (unsigned long) &__bitops_begin &&
+		     pc < (unsigned long) &__bitops_end))
+			pc = o7;
+
+		pc -= (unsigned long) &_stext;
+		pc >>= prof_shift;
+
+		spin_lock(&ticker_lock);
+		if(pc < prof_len)
+			prof_buffer[pc]++;
+		else
+			prof_buffer[prof_len - 1]++;
+		spin_unlock(&ticker_lock);
+	}
+}
+
 __volatile__ unsigned int *master_l10_counter;
 __volatile__ unsigned int *master_l10_limit;
 
@@ -81,6 +112,11 @@
 {
 	/* last time the cmos clock got updated */
 	static long last_rtc_update=0;
+
+#ifndef __SMP__
+	if(!user_mode(regs))
+		sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
+#endif
 
 #ifdef CONFIG_SUN4
 	if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile
--- v2.3.99-pre5/linux/arch/sparc/lib/Makefile	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/lib/Makefile	Wed Apr 12 09:12:34 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.33 2000/03/16 00:52:07 anton Exp $
+# $Id: Makefile,v 1.34 2000/03/31 04:06:20 davem Exp $
 # Makefile for Sparc library files..
 #
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/atomic.S linux/arch/sparc/lib/atomic.S
--- v2.3.99-pre5/linux/arch/sparc/lib/atomic.S	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/lib/atomic.S	Fri Apr 14 09:37:09 2000
@@ -10,6 +10,9 @@
 	.text
 	.align	4
 
+	.globl  __atomic_begin
+__atomic_begin:
+
 #ifndef __SMP__
 	.globl	___xchg32_sun4c
 ___xchg32_sun4c:
@@ -92,3 +95,6 @@
 	nop; nop; nop;			! Let the bits set
 	jmpl	%o7, %g0		! NOTE: not + 8, see callers in atomic.h
 	 mov	%g4, %o7		! Restore %o7
+
+	.globl  __atomic_end
+__atomic_end:
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/bitops.S linux/arch/sparc/lib/bitops.S
--- v2.3.99-pre5/linux/arch/sparc/lib/bitops.S	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/lib/bitops.S	Fri Apr 14 09:37:09 2000
@@ -10,6 +10,9 @@
 	.text
 	.align	4
 
+	.globl  __bitops_begin
+__bitops_begin:
+
 	/* Take bits in %g2 and set them in word at %g1,
 	 * return whether bits were set in original value
 	 * in %g2.  %g4 holds value to restore into %o7
@@ -159,3 +162,6 @@
 	nop; nop; nop
 	jmpl	%o7, %g0
 	 mov	%g4, %o7
+
+	.globl  __bitops_end
+__bitops_end:
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/copy_user.S linux/arch/sparc/lib/copy_user.S
--- v2.3.99-pre5/linux/arch/sparc/lib/copy_user.S	Tue Jan 11 22:31:38 2000
+++ linux/arch/sparc/lib/copy_user.S	Fri Apr 14 09:37:09 2000
@@ -112,6 +112,9 @@
 	.text
 	.align	4
 
+	.globl  __copy_user_begin
+__copy_user_begin:
+
 	.globl	C_LABEL(__copy_user)
 dword_align:
 	andcc	%o1, 1, %g0
@@ -482,3 +485,6 @@
 	sub	%o0, %g3, %o0
 	ba	fixupretl
 	 add	%g3, %o2, %g3
+
+	.globl  __copy_user_end
+__copy_user_end:
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v2.3.99-pre5/linux/arch/sparc/mm/Makefile	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/mm/Makefile	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.36 2000/01/29 01:09:05 anton Exp $
+# $Id: Makefile,v 1.37 2000/03/31 04:06:22 davem Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.3.99-pre5/linux/arch/sparc/mm/fault.c	Sun Feb 20 21:12:38 2000
+++ linux/arch/sparc/mm/fault.c	Tue Apr 25 17:52:01 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.114 2000/02/14 04:52:36 jj Exp $
+/* $Id: fault.c,v 1.115 2000/04/25 04:13:25 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -250,7 +250,7 @@
 	 * the fault.
 	 */
 	{
-		int fault = handle_mm_fault(tsk, vma, address, write);
+		int fault = handle_mm_fault(mm, vma, address, write);
 		if (fault < 0)
 			goto out_of_memory;
 		if (!fault)
@@ -450,7 +450,7 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	if (!handle_mm_fault(current, vma, address, write))
+	if (!handle_mm_fault(mm, vma, address, write))
 		goto do_sigbus;
 	up(&mm->mmap_sem);
 	return;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.99-pre5/linux/arch/sparc/mm/sun4c.c	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc/mm/sun4c.c	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.190 2000/02/14 04:52:34 jj Exp $
+/* $Id: sun4c.c,v 1.191 2000/04/08 02:11:41 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.99-pre5/linux/arch/sparc64/config.in	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc64/config.in	Mon Apr 24 13:59:57 2000
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.107 2000/03/29 11:56:51 davem Exp $
+# $Id: config.in,v 1.108 2000/04/18 05:20:45 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -187,6 +187,7 @@
 	 fi
       fi
       dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
+      dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
    fi
 
    endmenu
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.99-pre5/linux/arch/sparc64/defconfig	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc64/defconfig	Mon Apr 24 13:59:57 2000
@@ -223,8 +223,8 @@
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
@@ -246,6 +246,7 @@
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_VIA82CXXX_TUNING is not set
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 CONFIG_BLK_DEV_IDE_MODES=y
@@ -293,6 +294,7 @@
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
 # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 CONFIG_SCSI_QLOGIC_ISP=y
+CONFIG_SCSI_QLOGIC_FC=m
 
 #
 # Fibre Channel support
@@ -370,6 +372,7 @@
 CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 # CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
 CONFIG_AFFS_FS=m
 # CONFIG_HFS_FS is not set
 CONFIG_BFS_FS=m
@@ -379,47 +382,52 @@
 CONFIG_VFAT_FS=m
 CONFIG_EFS_FS=m
 CONFIG_CRAMFS=m
+CONFIG_RAMFS=m
 CONFIG_ISO9660_FS=m
-# CONFIG_JOLIET is not set
+CONFIG_JOLIET=y
 CONFIG_MINIX_FS=m
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_SYSV_FS=m
-# CONFIG_SYSV_FS_WRITE is not set
+CONFIG_SYSV_FS_WRITE=y
 CONFIG_UDF_FS=m
-# CONFIG_UDF_RW is not set
+CONFIG_UDF_RW=y
 CONFIG_UFS_FS=m
-# CONFIG_UFS_FS_WRITE is not set
+CONFIG_UFS_FS_WRITE=y
 
 #
 # Network File Systems
 #
 CONFIG_CODA_FS=m
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=m
-# CONFIG_NFSD_V3 is not set
+CONFIG_NFSD_V3=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
 CONFIG_SMB_FS=m
 CONFIG_NCP_FS=m
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_MOUNT_SUBDIR=y
+CONFIG_NCPFS_NDS_DOMAINS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
 
 #
 # Partition Types
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.3.99-pre5/linux/arch/sparc64/kernel/Makefile	Tue Apr 11 15:09:14 2000
+++ linux/arch/sparc64/kernel/Makefile	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.52 2000/03/19 07:00:29 ecd Exp $
+# $Id: Makefile,v 1.53 2000/03/31 04:06:22 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/binfmt_aout32.c	Mon Mar 27 08:08:22 2000
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Thu Apr 13 08:11:48 2000
@@ -198,7 +198,6 @@
 static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
 	struct exec ex;
-	int fd;
 	unsigned long error;
 	unsigned long fd_offset;
 	unsigned long rlim;
@@ -230,7 +229,7 @@
 		return retval;
 
 	/* OK, This is the point of no return */
-	current->personality = PER_LINUX;
+	set_personality(PER_SUNOS);
 
 	current->mm->end_code = ex.a_text +
 		(current->mm->start_code = N_TXTADDR(ex));
@@ -270,15 +269,8 @@
 			error_time = jiffies;
 		}
 
-		fd = get_unused_fd();
-		if (fd < 0)
-			return fd;
-		get_file(bprm->file);
-		fd_install(fd, bprm->file);
-
 		if (!bprm->file->f_op->mmap) {
 			loff_t pos = fd_offset;
-			sys_close(fd);
 			do_brk(0, ex.a_text+ex.a_data);
 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 				  ex.a_text+ex.a_data, &pos);
@@ -291,7 +283,6 @@
 			fd_offset);
 
 		if (error != N_TXTADDR(ex)) {
-			sys_close(fd);
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
@@ -300,20 +291,13 @@
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
-		sys_close(fd);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
 	}
 beyond_if:
-	put_exec_domain(current->exec_domain);
-	if (current->binfmt && current->binfmt->module)
-		__MOD_DEC_USE_COUNT(current->binfmt->module);
-	current->exec_domain = lookup_exec_domain(current->personality);
-	current->binfmt = &aout32_format;
-	if (current->binfmt && current->binfmt->module)
-		__MOD_INC_USE_COUNT(current->binfmt->module);
+	set_binfmt(&aout32_format);
 
 	set_brk(current->mm->start_brk, current->mm->brk);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/ioctl32.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/ioctl32.c	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.87 2000/03/30 02:09:07 davem Exp $
+/* $Id: ioctl32.c,v 1.88 2000/04/14 10:10:34 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -1816,6 +1816,7 @@
 #define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
 #define ATM_GETLOOP32	  _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
 #define ATM_SETLOOP32	  _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
+#define ATM_QUERYLOOP32	  _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32)
 
 static struct {
         unsigned int cmd32;
@@ -1836,7 +1837,8 @@
 	{ ATM_GETSTAT32,     ATM_GETSTAT },
 	{ ATM_GETSTATZ32,    ATM_GETSTATZ },
 	{ ATM_GETLOOP32,     ATM_GETLOOP },
-	{ ATM_SETLOOP32,     ATM_SETLOOP }
+	{ ATM_SETLOOP32,     ATM_SETLOOP },
+	{ ATM_QUERYLOOP32,   ATM_QUERYLOOP }
 };
 
 #define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0]))
@@ -1996,6 +1998,7 @@
 	case ATM_GETSTATZ:
 	case ATM_GETLOOP:
 	case ATM_SETLOOP:
+	case ATM_QUERYLOOP:
                 return do_atmif_sioc(fd, cmd, arg);
         }
 
@@ -3110,6 +3113,7 @@
 HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
 HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl)
 HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl)
 HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
 HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
 HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/irq.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/sparc64/kernel/irq.c	Mon Apr 24 13:59:57 2000
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.85 2000/03/02 02:00:24 davem Exp $
+/* $Id: irq.c,v 1.86 2000/04/15 06:02:50 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -538,82 +538,43 @@
 }
 
 /* Only uniprocessor needs this IRQ/BH locking depth, on SMP it
- * lives in the per-cpu structure for cache reasons.
+ * lives in the brlock table for cache reasons.
  */
 #ifndef __SMP__
 unsigned int local_irq_count;
 unsigned int local_bh_count;
-
-#define irq_enter(cpu, irq)	(local_irq_count++)
-#define irq_exit(cpu, irq)	(local_irq_count--)
 #else
 
 /* Who has global_irq_lock. */
 unsigned char global_irq_holder = NO_PROC_ID;
 
-/* This protects IRQ's. */
-spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
-
-/* Global IRQ locking depth. */
-atomic_t global_irq_count = ATOMIC_INIT(0);
-
-#define irq_enter(cpu, irq)			\
-do {	hardirq_enter(cpu);			\
-	spin_unlock_wait(&global_irq_lock);	\
-} while(0)
-#define irq_exit(cpu, irq)	hardirq_exit(cpu)
-
 static void show(char * str)
 {
 	int cpu = smp_processor_id();
+	int i;
 
 	printk("\n%s, CPU %d:\n", str, cpu);
-	printk("irq:  %d [%u %u]\n",
-	       atomic_read(&global_irq_count),
-	       cpu_data[0].irq_count, cpu_data[1].irq_count);
-	printk("bh:   %d [%u %u]\n",
-	       (spin_is_locked(&global_bh_lock) ? 1 : 0),
-	       cpu_data[0].bh_count, cpu_data[1].bh_count);
+	printk("irq:  %d [ ", irqs_running());
+	for (i = 0; i < smp_num_cpus; i++)
+		printk("%u ", __brlock_array[i][BR_GLOBALIRQ_LOCK]);
+	printk("]\nbh:   %d [ ",
+	       (spin_is_locked(&global_bh_lock) ? 1 : 0));
+	for (i = 0; i < smp_num_cpus; i++)
+		printk("%u ", cpu_data[i].bh_count);
+	printk("]\n");
 }
 
 #define MAXCOUNT 100000000
 
+#if 0
 #define SYNC_OTHER_ULTRAS(x)	udelay(x+1)
-
-static inline void wait_on_irq(int cpu)
-{
-	int count = MAXCOUNT;
-	for(;;) {
-		membar("#LoadLoad");
-		if (!atomic_read (&global_irq_count)) {
-			if (local_bh_count || ! spin_is_locked(&global_bh_lock))
-				break;
-		}
-		spin_unlock (&global_irq_lock);
-		membar("#StoreLoad | #StoreStore");
-		for(;;) {
-			if (!--count) {
-				show("wait_on_irq");
-				count = ~0;
-			}
-			__sti();
-			SYNC_OTHER_ULTRAS(cpu);
-			__cli();
-			if (atomic_read(&global_irq_count))
-				continue;
-			if (spin_is_locked (&global_irq_lock))
-				continue;
-			if (!local_bh_count && spin_is_locked (&global_bh_lock))
-				continue;
-			if (spin_trylock(&global_irq_lock))
-				break;
-		}
-	}
-}
+#else
+#define SYNC_OTHER_ULTRAS(x)	membar("#Sync");
+#endif
 
 void synchronize_irq(void)
 {
-	if (atomic_read(&global_irq_count)) {
+	if (irqs_running()) {
 		cli();
 		sti();
 	}
@@ -621,15 +582,37 @@
 
 static inline void get_irqlock(int cpu)
 {
-	if (! spin_trylock(&global_irq_lock)) {
-		if ((unsigned char) cpu == global_irq_holder)
-			return;
-		do {
-			while (spin_is_locked (&global_irq_lock))
-				membar("#LoadLoad");
-		} while(! spin_trylock(&global_irq_lock));
+	int count;
+
+	if ((unsigned char)cpu == global_irq_holder)
+		return;
+
+	count = MAXCOUNT;
+again:
+	br_write_lock(BR_GLOBALIRQ_LOCK);
+	for (;;) {
+		spinlock_t *lock;
+
+		if (!irqs_running() &&
+		    (local_bh_count || !spin_is_locked(&global_bh_lock)))
+			break;
+
+		br_write_unlock(BR_GLOBALIRQ_LOCK);
+		lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock;
+		while (irqs_running() ||
+		       spin_is_locked(lock) ||
+		       (!local_bh_count && spin_is_locked(&global_bh_lock))) {
+			if (!--count) {
+				show("wait_on_irq");
+				count = (~0 >> 1);
+			}
+			__sti();
+			SYNC_OTHER_ULTRAS(cpu);
+			__cli();
+		}
+		goto again;
 	}
-	wait_on_irq(cpu);
+
 	global_irq_holder = cpu;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/pci_common.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/pci_common.c	Wed Apr 26 12:13:16 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.7 2000/03/25 05:18:11 davem Exp $
+/* $Id: pci_common.c,v 1.11 2000/04/26 10:48:02 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -66,6 +66,27 @@
 	kfree(pdev);
 }
 
+/* Older versions of OBP on PCI systems encode 64-bit MEM
+ * space assignments incorrectly, this fixes them up.
+ */
+static void __init fixup_obp_assignments(struct pcidev_cookie *pcp)
+{
+	int i;
+
+	for (i = 0; i < pcp->num_prom_assignments; i++) {
+		struct linux_prom_pci_registers *ap;
+		int space;
+
+		ap = &pcp->prom_assignments[i];
+		space = ap->phys_hi >> 24;
+		if ((space & 0x3) == 2 &&
+		    (space & 0x4) != 0) {
+			ap->phys_hi &= ~(0x7 << 24);
+			ap->phys_hi |= 0x3 << 24;
+		}
+	}
+}
+
 /* Fill in the PCI device cookie sysdata for the given
  * PCI device.  This cookie is the means by which one
  * can get to OBP and PCI controller specific information
@@ -147,6 +168,8 @@
 				(err / sizeof(pcp->prom_assignments[0]));
 	}
 
+	fixup_obp_assignments(pcp);
+
 	pdev->sysdata = pcp;
 }
 
@@ -219,10 +242,15 @@
 		return &pbm->mem_space;
 
 	case 3:
+		/* 64-bit MEM space, these are allocated out of
+		 * the 32-bit mem_space range for the PBM, ie.
+		 * we just zero out the upper 32-bits.
+		 */
+		return &pbm->mem_space;
+
 	default:
-		/* 64-bit MEM space, unsupported. */
-		printk("PCI: 64-bit MEM assignment??? "
-		       "Tell davem@redhat.com about it!\n");
+		printk("PCI: What is resource space %x? "
+		       "Tell davem@redhat.com about it!\n", space);
 		return NULL;
 	};
 }
@@ -231,6 +259,7 @@
 __init get_device_resource(struct linux_prom_pci_registers *ap,
 			   struct pci_dev *pdev)
 {
+	struct resource *res;
 	int breg = (ap->phys_hi & 0xff);
 	int space = (ap->phys_hi >> 24) & 3;
 
@@ -240,7 +269,8 @@
 		if (space != 2)
 			bad_assignment(ap, NULL, 0);
 
-		return &pdev->resource[PCI_ROM_RESOURCE];
+		res = &pdev->resource[PCI_ROM_RESOURCE];
+		break;
 
 	case PCI_BASE_ADDRESS_0:
 	case PCI_BASE_ADDRESS_1:
@@ -248,12 +278,16 @@
 	case PCI_BASE_ADDRESS_3:
 	case PCI_BASE_ADDRESS_4:
 	case PCI_BASE_ADDRESS_5:
-		return &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4];
+		res = &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4];
+		break;
 
 	default:
 		bad_assignment(ap, NULL, 0);
-		return NULL;
+		res = NULL;
+		break;
 	};
+
+	return res;
 }
 
 static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
@@ -281,6 +315,31 @@
 		if ((res->start & 0xffffffffUL) != ap->phys_lo)
 			bad_assignment(ap, res, 1);
 
+		/* If it is a 64-bit MEM space assignment, verify that
+		 * the resource is too and that the upper 32-bits match.
+		 */
+		if (((ap->phys_hi >> 24) & 3) == 3) {
+			if (((res->flags & IORESOURCE_MEM) == 0) ||
+			    ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+			     != PCI_BASE_ADDRESS_MEM_TYPE_64))
+				bad_assignment(ap, res, 1);
+			if ((res->start >> 32) != ap->phys_mid)
+				bad_assignment(ap, res, 1);
+
+			/* PBM cannot generate cpu initiated PIOs
+			 * to the full 64-bit space.  Therefore the
+			 * upper 32-bits better be zero.  If it is
+			 * not, just skip it and we will assign it
+			 * properly ourselves.
+			 */
+			if ((res->start >> 32) != 0UL) {
+				printk(KERN_ERR "PCI: OBP assigns out of range MEM address "
+				       "%016lx for region %ld on device %s\n",
+				       res->start, (res - &pdev->resource[0]), pdev->name);
+				continue;
+			}
+		}
+
 		/* Adjust the resource into the physical address space
 		 * of this PBM.
 		 */
@@ -425,13 +484,21 @@
 		return 0;
 
 	/* If we are underneath a PCI bridge, use PROM register
-	 * property of parent bridge.
+	 * property of the parent bridge which is closest to
+	 * the PBM.
 	 */
 	if (pdev->bus->number != pbm->pci_first_busno) {
 		struct pcidev_cookie *bus_pcp;
+		struct pci_dev *pwalk;
 		int offset;
 
-		bus_pcp = pdev->bus->self->sysdata;
+		pwalk = pdev->bus->self;
+		while (pwalk->bus &&
+		       pwalk->bus->number != pbm->pci_first_busno)
+			pwalk = pwalk->bus->self;
+
+		bus_pcp = pwalk->bus->self->sysdata;
+
 		pregs = bus_pcp->prom_regs;
 		offset = prom_getint(bus_pcp->prom_node,
 				     "fcode-rom-offset");
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/pci_psycho.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/pci_psycho.c	Mon Apr 24 13:59:58 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.15 2000/03/25 05:18:11 davem Exp $
+/* $Id: pci_psycho.c,v 1.16 2000/04/15 10:06:16 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1074,22 +1074,34 @@
 {
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm = pcp->pbm;
-	struct resource *res = &pdev->resource[resource];
-	struct resource *root;
+	struct resource *res, *root;
 	u32 reg;
-	int where, size;
+	int where, size, is_64bit;
 
+	res = &pdev->resource[resource];
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+
+	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
 		root = &pbm->io_space;
-	else
+	else {
 		root = &pbm->mem_space;
+		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
+			is_64bit = 1;
+	}
 
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
 	size = res->end - res->start;
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - root->start)) & ~size));
 	pci_write_config_dword(pdev, where, reg);
+
+	/* This knows that the upper 32-bits of the address
+	 * must be zero.  Our PCI common layer enforces this.
+	 */
+	if (is_64bit)
+		pci_write_config_dword(pdev, where + 4, 0);
 }
 
 /* We have to do the config space accesses by hand, thus... */
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/pci_sabre.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/pci_sabre.c	Mon Apr 24 13:59:58 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.16 2000/03/25 05:18:12 davem Exp $
+/* $Id: pci_sabre.c,v 1.19 2000/04/15 13:07:51 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1012,22 +1012,35 @@
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm = pcp->pbm;
 	struct pci_controller_info *p = pbm->parent;
-	struct resource *res = &pdev->resource[resource];
+	struct resource *res;
 	unsigned long base;
 	u32 reg;
-	int where, size;
+	int where, size, is_64bit;
 
+	res = &pdev->resource[resource];
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+
+	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
 		base = p->controller_regs + SABRE_IOSPACE;
-	else
+	else {
 		base = p->controller_regs + SABRE_MEMSPACE;
+		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
+			is_64bit = 1;
+	}
 
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
 	size = res->end - res->start;
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - base)) & ~size));
 	pci_write_config_dword(pdev, where, reg);
+
+	/* This knows that the upper 32-bits of the address
+	 * must be zero.  Our PCI common layer enforces this.
+	 */
+	if (is_64bit)
+		pci_write_config_dword(pdev, where + 4, 0);
 }
 
 static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
@@ -1050,6 +1063,20 @@
 			/* Status register bits are "write 1 to clear". */
 			sabre_write_word(pdev, PCI_STATUS, 0xffff);
 			sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff);
+
+			/* Use a primary/seconday latency timer value
+			 * of 64.
+			 */
+			sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64);
+			sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
+
+			/* Enable reporting/forwarding of master aborts,
+			 * parity, and SERR.
+			 */
+			sabre_write_byte(pdev, PCI_BRIDGE_CONTROL,
+					 (PCI_BRIDGE_CTL_PARITY |
+					  PCI_BRIDGE_CTL_SERR |
+					  PCI_BRIDGE_CTL_MASTER_ABORT));
 		}
 	}
 }
@@ -1086,17 +1113,6 @@
 	sabre_bus = pci_scan_bus(p->pci_first_busno,
 				 p->pci_ops,
 				 &p->pbm_A);
-
-	{
-		unsigned int devfn;
-		u8 *addr;
-
-		devfn = PCI_DEVFN(0, 0);
-		addr = sabre_pci_config_mkaddr(&p->pbm_A, 0,
-					       devfn, PCI_LATENCY_TIMER);
-		pci_config_write8(addr, 32);
-	}
-
 	apb_init(p, sabre_bus);
 
 	walk = &sabre_bus->children;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/power.c linux/arch/sparc64/kernel/power.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/power.c	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/power.c	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: power.c,v 1.5 1999/12/19 23:28:00 davem Exp $
+/* $Id: power.c,v 1.6 2000/04/13 00:59:59 davem Exp $
  * power.c: Power management driver.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -55,8 +55,7 @@
 	static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
 	char *argv[] = { "/usr/bin/shutdown", "-h", "now", NULL };
 
-	current->session = 1;
-	current->pgrp = 1;
+	daemonize();
 	sprintf(current->comm, "powerd");
 
 again:
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/process.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/process.c	Mon Apr 24 13:59:58 2000
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.105 2000/03/26 09:13:48 davem Exp $
+/*  $Id: process.c,v 1.106 2000/04/15 06:02:50 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -269,9 +269,8 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&regdump_lock, flags);
-	printk("CPU[%d]: local_irq_count[%u] global_irq_count[%d]\n",
-	       smp_processor_id(), local_irq_count,
-	       atomic_read(&global_irq_count));
+	printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n",
+	       smp_processor_id(), local_irq_count, irqs_running());
 #endif
 	printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
 	       regs->tpc, regs->tnpc, regs->y);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/ptrace.c	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc64/kernel/ptrace.c	Wed Apr 12 09:16:32 2000
@@ -68,7 +68,7 @@
 static void
 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
 {
-	if (current->personality & PER_BSD)
+	if (current->personality == PER_SUNOS)
 		pt_succ_return (regs, val);
 	else
 		pt_succ_return_linux (regs, val, addr);
@@ -164,8 +164,8 @@
 		goto out;
 	}
 
-	if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH))
-	    || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) {
+	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
+	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
 		unsigned long flags;
 
 		if(child == current) {
@@ -203,9 +203,7 @@
 		pt_succ_return(regs, 0);
 		goto out;
 	}
-	if (!(child->flags & PF_PTRACED)
-	    && ((current->personality & PER_BSD) && (request != PTRACE_SUNATTACH))
-	    && (!(current->personality & PER_BSD) && (request != PTRACE_ATTACH))) {
+	if (!(child->flags & PF_PTRACED)) {
 		pt_error_return(regs, ESRCH);
 		goto out;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/sbus.c	Fri Mar 10 16:40:41 2000
+++ linux/arch/sparc64/kernel/sbus.c	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.10 2000/03/10 07:52:08 davem Exp $
+/* $Id: sbus.c,v 1.11 2000/04/14 09:13:04 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -315,7 +315,7 @@
 dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int dir)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
-	unsigned long npages, phys_base, flags;
+	unsigned long npages, pbase, flags;
 	iopte_t *iopte;
 	u32 dma_base, offset;
 	unsigned long iopte_bits;
@@ -323,10 +323,10 @@
 	if (dir == SBUS_DMA_NONE)
 		BUG();
 
-	phys_base = (unsigned long) ptr;
-	offset = (u32) (phys_base & ~PAGE_MASK);
-	size = (PAGE_ALIGN(phys_base + size) - (phys_base & PAGE_MASK));
-	phys_base = (unsigned long) __pa(phys_base & PAGE_MASK);
+	pbase = (unsigned long) ptr;
+	offset = (u32) (pbase & ~PAGE_MASK);
+	size = (PAGE_ALIGN(pbase + size) - (pbase & PAGE_MASK));
+	pbase = (unsigned long) __pa(pbase & PAGE_MASK);
 
 	spin_lock_irqsave(&iommu->lock, flags);
 	npages = size >> PAGE_SHIFT;
@@ -337,8 +337,8 @@
 	if (dir != SBUS_DMA_TODEVICE)
 		iopte_bits |= IOPTE_WRITE;
 	while (npages--) {
-		*iopte++ = __iopte(iopte_bits | (phys_base & IOPTE_PAGE));
-		phys_base += PAGE_SIZE;
+		*iopte++ = __iopte(iopte_bits | (pbase & IOPTE_PAGE));
+		pbase += PAGE_SIZE;
 	}
 	npages = size >> PAGE_SHIFT;
 	spin_unlock_irqrestore(&iommu->lock, flags);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/signal.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/signal.c	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.48 1999/12/15 22:24:52 davem Exp $
+/*  $Id: signal.c,v 1.49 2000/04/08 02:11:46 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/signal32.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/signal32.c	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.60 2000/02/25 06:02:37 jj Exp $
+/*  $Id: signal32.c,v 1.62 2000/04/12 08:10:19 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -750,8 +750,7 @@
 			goto sigsegv;
 
 		if(pte_present(*ptep)) {
-			unsigned long page = (unsigned long)
-				__va(pte_pagenr(*ptep) << PAGE_SHIFT);
+			unsigned long page = page_address(pte_page(*ptep));
 
 			__asm__ __volatile__("
 			membar	#StoreStore
@@ -1176,8 +1175,7 @@
 			goto sigsegv;
 
 		if(pte_present(*ptep)) {
-			unsigned long page = (unsigned long)
-				__va(pte_pagenr(*ptep) << PAGE_SHIFT);
+			unsigned long page = page_address(pte_page(*ptep));
 
 			__asm__ __volatile__("
 			membar	#StoreStore
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/smp.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/smp.c	Mon Apr 24 13:59:58 2000
@@ -87,7 +87,6 @@
 {
 	int i;
 
-	cpu_data[id].irq_count			= 0;
 	cpu_data[id].bh_count			= 0;
 	/* multiplier and counter set by
 	   smp_setup_percpu_timer()  */
@@ -627,33 +626,7 @@
 		smp_cross_call(&xcall_promstop, 0, 0, 0);
 }
 
-static inline void sparc64_do_profile(unsigned long pc, unsigned long o7)
-{
-	if (prof_buffer && current->pid) {
-		extern int _stext;
-		extern int rwlock_impl_begin, rwlock_impl_end;
-		extern int atomic_impl_begin, atomic_impl_end;
-		extern int __memcpy_begin, __memcpy_end;
-		extern int __bitops_begin, __bitops_end;
-
-		if ((pc >= (unsigned long) &atomic_impl_begin &&
-		     pc < (unsigned long) &atomic_impl_end) ||
-		    (pc >= (unsigned long) &rwlock_impl_begin &&
-		     pc < (unsigned long) &rwlock_impl_end) ||
-		    (pc >= (unsigned long) &__memcpy_begin &&
-		     pc < (unsigned long) &__memcpy_end) ||
-		    (pc >= (unsigned long) &__bitops_begin &&
-		     pc < (unsigned long) &__bitops_end))
-			pc = o7;
-
-		pc -= (unsigned long) &_stext;
-		pc >>= prof_shift;
-
-		if(pc >= prof_len)
-			pc = prof_len - 1;
-		atomic_inc((atomic_t *)&prof_buffer[pc]);
-	}
-}
+extern void sparc64_do_profile(unsigned long pc, unsigned long o7);
 
 static unsigned long current_tick_offset;
 
@@ -682,40 +655,29 @@
 
 	clear_softint((1UL << 0));
 	do {
-		if(!user)
+		if (!user)
 			sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
-		if(!--prof_counter(cpu))
-		{
+		if (!--prof_counter(cpu)) {
 			if (cpu == boot_cpu_id) {
-/* XXX Keep this in sync with irq.c --DaveM */
-#define irq_enter(cpu, irq)			\
-do {	hardirq_enter(cpu);			\
-	spin_unlock_wait(&global_irq_lock);	\
-} while(0)
-#define irq_exit(cpu, irq)	hardirq_exit(cpu)
-
 				irq_enter(cpu, 0);
-				kstat.irqs[cpu][0]++;
 
+				kstat.irqs[cpu][0]++;
 				timer_tick_interrupt(regs);
 
 				irq_exit(cpu, 0);
-
-#undef irq_enter
-#undef irq_exit
 			}
 
-			if(current->pid) {
+			if (current->pid) {
 				unsigned int *inc, *inc2;
 
 				update_one_process(current, 1, user, !user, cpu);
-				if(--current->counter <= 0) {
+				if (--current->counter <= 0) {
 					current->counter = 0;
 					current->need_resched = 1;
 				}
 
-				if(user) {
-					if(current->priority < DEF_PRIORITY) {
+				if (user) {
+					if (current->priority < DEF_PRIORITY) {
 						inc = &kstat.cpu_nice;
 						inc2 = &kstat.per_cpu_nice[cpu];
 					} else {
@@ -862,7 +824,7 @@
 
 static void __init smp_tune_scheduling (void)
 {
-	unsigned long flush_base, flags, *p;
+	unsigned long orig_flush_base, flush_base, flags, *p;
 	unsigned int ecache_size, order;
 	cycles_t tick1, tick2, raw;
 
@@ -881,7 +843,8 @@
 					 "ecache-size", (512 * 1024));
 	if (ecache_size > (4 * 1024 * 1024))
 		ecache_size = (4 * 1024 * 1024);
-	flush_base = __get_free_pages(GFP_KERNEL, order = get_order(ecache_size));
+	orig_flush_base = flush_base =
+		__get_free_pages(GFP_KERNEL, order = get_order(ecache_size));
 
 	if (flush_base != 0UL) {
 		__save_and_cli(flags);
@@ -923,7 +886,7 @@
 		 */
 		cacheflush_time = (raw - (raw >> 2));
 
-		free_pages(flush_base, order);
+		free_pages(orig_flush_base, order);
 	} else {
 		cacheflush_time = ((ecache_size << 2) +
 				   (ecache_size << 1));
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Apr 24 13:59:58 2000
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.80 2000/03/27 10:38:47 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.83 2000/04/19 08:38:25 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -81,6 +81,8 @@
 extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
 extern long sparc32_open(const char * filename, int flags, int mode);
+extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
+extern int unregister_ioctl32_conversion(unsigned int cmd);
                 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
@@ -129,8 +131,6 @@
 
 /* Hard IRQ locking */
 EXPORT_SYMBOL(global_irq_holder);
-EXPORT_SYMBOL(global_irq_lock);
-EXPORT_SYMBOL(global_irq_count);
 EXPORT_SYMBOL(synchronize_irq);
 EXPORT_SYMBOL_PRIVATE(global_cli);
 EXPORT_SYMBOL_PRIVATE(global_sti);
@@ -219,6 +219,10 @@
 EXPORT_SYMBOL(pci_dma_supported);
 #endif
 
+/* IOCTL32 emulation hooks. */
+EXPORT_SYMBOL(register_ioctl32_conversion);
+EXPORT_SYMBOL(unregister_ioctl32_conversion);
+
 /* Solaris/SunOS binary compatibility */
 EXPORT_SYMBOL(_sigpause_common);
 
@@ -297,8 +301,8 @@
 /* Special internal versions of library functions. */
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
-EXPORT_SYMBOL(clear_page);
-EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(_clear_page);
+EXPORT_SYMBOL(_copy_page);
 EXPORT_SYMBOL(clear_user_page);
 EXPORT_SYMBOL(copy_user_page);
 EXPORT_SYMBOL(__bzero);
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/kernel/sys_sparc.c	Wed Apr 26 09:25:17 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.37 2000/03/17 05:48:46 anton Exp $
+/* $Id: sys_sparc.c,v 1.38 2000/04/13 07:30:34 jj Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -23,6 +23,7 @@
 #include <linux/smp_lock.h>
 #include <linux/malloc.h>
 #include <linux/ipc.h>
+#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -182,6 +183,33 @@
 	return err;
 }
 
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
+asmlinkage int sparc64_newuname(struct new_utsname * name)
+{
+	int ret = sys_newuname(name);
+	
+	if (current->personality == PER_LINUX32 && !ret) {
+		ret = copy_to_user(name->machine, "sparc\0\0", 8);
+	}
+	return ret;
+}
+
+extern asmlinkage long sys_personality(unsigned long);
+
+asmlinkage int sparc64_personality(unsigned long personality)
+{
+	int ret;
+	lock_kernel();
+	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	unlock_kernel();
+	if (ret == PER_LINUX32)
+		ret = PER_LINUX;
+	return ret;
+}
+
 /* Linux version of mmap */
 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags, unsigned long fd,
@@ -232,7 +260,7 @@
 	    (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET))
 		return -EINVAL;
 	down(&current->mm->mmap_sem);
-	ret = do_munmap(addr, len);
+	ret = do_munmap(current->mm, addr, len);
 	up(&current->mm->mmap_sem);
 	return ret;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc32.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.142 2000/03/24 04:17:38 davem Exp $
+/* $Id: sys_sparc32.c,v 1.145 2000/04/13 07:30:34 jj Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -3542,6 +3542,18 @@
 	s32			gf32_version;
 };
 
+struct nfsctl_fdparm32 {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	s32			gd32_version;
+};
+
+struct nfsctl_fsparm32 {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	s32			gd32_maxlen;
+};
+
 struct nfsctl_arg32 {
 	s32			ca32_version;	/* safeguard */
 	union {
@@ -3550,15 +3562,17 @@
 		struct nfsctl_export32	u32_export;
 		struct nfsctl_uidmap32	u32_umap;
 		struct nfsctl_fhparm32	u32_getfh;
-		u32			u32_debug;
+		struct nfsctl_fdparm32	u32_getfd;
+		struct nfsctl_fsparm32	u32_getfs;
 	} u;
 #define ca32_svc	u.u32_svc
 #define ca32_client	u.u32_client
 #define ca32_export	u.u32_export
 #define ca32_umap	u.u32_umap
 #define ca32_getfh	u.u32_getfh
+#define ca32_getfd	u.u32_getfd
+#define ca32_getfs	u.u32_getfs
 #define ca32_authd	u.u32_authd
-#define ca32_debug	u.u32_debug
 };
 
 union nfsctl_res32 {
@@ -3689,6 +3703,38 @@
 	return err;
 }
 
+static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfd.gd_addr,
+			  &arg32->ca32_getfd.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= copy_from_user(&karg->ca_getfd.gd_path,
+			  &arg32->ca32_getfd.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= __get_user(karg->ca_getfd.gd_version,
+		      &arg32->ca32_getfd.gd32_version);
+	return err;
+}
+
+static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfs.gd_addr,
+			  &arg32->ca32_getfs.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= copy_from_user(&karg->ca_getfs.gd_path,
+			  &arg32->ca32_getfs.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= __get_user(karg->ca_getfs.gd_maxlen,
+		      &arg32->ca32_getfs.gd32_maxlen);
+	return err;
+}
+
 /* This really doesn't need translations, we are only passing
  * back a union which contains opaque nfs file handle data.
  */
@@ -3727,6 +3773,7 @@
 		err = nfs_clnt32_trans(karg, arg32);
 		break;
 	case NFSCTL_EXPORT:
+	case NFSCTL_UNEXPORT:
 		err = nfs_exp32_trans(karg, arg32);
 		break;
 	/* This one is unimplemented, be we're ready for it. */
@@ -3736,6 +3783,12 @@
 	case NFSCTL_GETFH:
 		err = nfs_getfh32_trans(karg, arg32);
 		break;
+	case NFSCTL_GETFD:
+		err = nfs_getfd32_trans(karg, arg32);
+		break;
+	case NFSCTL_GETFS:
+		err = nfs_getfs32_trans(karg, arg32);
+		break;
 	default:
 		err = -EINVAL;
 		break;
@@ -3747,7 +3800,12 @@
 	err = sys_nfsservctl(cmd, karg, kres);
 	set_fs(oldfs);
 
-	if(!err && cmd == NFSCTL_GETFH)
+	if (err)
+		goto done;
+
+	if((cmd == NFSCTL_GETFH) ||
+	   (cmd == NFSCTL_GETFD) ||
+	   (cmd == NFSCTL_GETFS))
 		err = nfs_getfh32_res_trans(kres, res32);
 
 done:
@@ -3922,18 +3980,6 @@
 }
 
 
-extern asmlinkage int sys_newuname(struct new_utsname * name);
-
-asmlinkage int sys32_newuname(struct new_utsname * name)
-{
-	int ret = sys_newuname(name);
-	
-	if (current->personality == PER_LINUX32 && !ret) {
-		ret = copy_to_user(name->machine, "sparc\0\0", 8);
-	}
-	return ret;
-}
-
 extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
 				    size_t count, loff_t pos);
 
@@ -3954,21 +4000,6 @@
 	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-
-extern asmlinkage long sys_personality(unsigned long);
-
-asmlinkage int sys32_personality(unsigned long personality)
-{
-	int ret;
-	lock_kernel();
-	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
-		personality = PER_LINUX32;
-	ret = sys_personality(personality);
-	unlock_kernel();
-	if (ret == PER_LINUX32)
-		ret = PER_LINUX;
-	return ret;
-}
 
 extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sunos32.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Wed Apr 26 09:25:17 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.43 2000/03/26 11:28:53 davem Exp $
+/* $Id: sys_sunos32.c,v 1.45 2000/04/13 00:55:49 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -45,6 +45,7 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/nfs.h>
+#include <linux/nfs2.h>
 #include <linux/nfs_mount.h>
 
 /* for sunos_select */
@@ -69,7 +70,6 @@
 
 	down(&current->mm->mmap_sem);
 	lock_kernel();
-	current->personality |= PER_BSD;
 	if(flags & MAP_NORESERVE) {
 		static int cnt;
 		if (cnt++ < 10)
@@ -141,7 +141,7 @@
 	/* Always allow shrinking brk. */
 	if (brk <= current->mm->brk) {
 		current->mm->brk = brk;
-		do_munmap(newbrk, oldbrk-newbrk);
+		do_munmap(current->mm, newbrk, oldbrk-newbrk);
 		goto out;
 	}
 	/* Check against rlimit and stack.. */
@@ -549,7 +549,6 @@
 
 	/* SunOS binaries expect that select won't change the tvp contents */
 	lock_kernel();
-	current->personality |= STICKY_TIMEOUTS;
 	ret = sys32_select (width, inp, outp, exp, tvp_x);
 	if (ret == -EINTR && tvp_x) {
 		struct timeval32 *tvp = (struct timeval32 *)A(tvp_x);
@@ -685,7 +684,7 @@
 	 * address to create a socket and bind it to a reserved
 	 * port on this system
 	 */
-	if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))
+	if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount)))
 		return -EFAULT;
 
 	server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -776,14 +775,14 @@
 		dev_fname = getname(data);
 	} else if(strcmp(type_page, "nfs") == 0) {
 		ret = sunos_nfs_mount (dir_page, flags, data);
-		goto out2
+		goto out2;
         } else if(strcmp(type_page, "ufs") == 0) {
 		printk("Warning: UFS filesystem mounts unsupported.\n");
 		ret = -ENODEV;
-		goto out2
+		goto out2;
 	} else if(strcmp(type_page, "proc")) {
 		ret = -ENODEV;
-		goto out2
+		goto out2;
 	}
 	ret = PTR_ERR(dev_fname);
 	if (IS_ERR(dev_fname))
@@ -1214,7 +1213,6 @@
 {
 	const char *filename = (const char *)(long)fname;
 
-	current->personality |= PER_BSD;
 	return sparc32_open(filename, flags, mode);
 }
 
@@ -1349,8 +1347,6 @@
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
-
-	current->personality |= PER_BSD;
 
 	if (act) {
 		old_sigset_t32 mask;
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.3.99-pre5/linux/arch/sparc64/kernel/systbls.S	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/kernel/systbls.S	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.71 2000/03/15 02:43:36 davem Exp $
+/* $Id: systbls.S,v 1.72 2000/04/13 07:30:34 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -56,8 +56,8 @@
 /*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
 	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/	.word sys32_init_module, sys32_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
+/*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
 	.word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
@@ -115,8 +115,8 @@
 /*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
 	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/	.word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
+/*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
 	.word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- v2.3.99-pre5/linux/arch/sparc64/kernel/time.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/sparc64/kernel/time.c	Fri Apr 14 09:37:09 2000
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.24 2000/03/02 02:00:25 davem Exp $
+/* $Id: time.c,v 1.25 2000/04/13 05:29:44 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -67,6 +67,34 @@
 	}
 }
 
+void sparc64_do_profile(unsigned long pc, unsigned long o7)
+{
+	if (prof_buffer && current->pid) {
+		extern int _stext;
+		extern int rwlock_impl_begin, rwlock_impl_end;
+		extern int atomic_impl_begin, atomic_impl_end;
+		extern int __memcpy_begin, __memcpy_end;
+		extern int __bitops_begin, __bitops_end;
+
+		if ((pc >= (unsigned long) &atomic_impl_begin &&
+		     pc < (unsigned long) &atomic_impl_end) ||
+		    (pc >= (unsigned long) &rwlock_impl_begin &&
+		     pc < (unsigned long) &rwlock_impl_end) ||
+		    (pc >= (unsigned long) &__memcpy_begin &&
+		     pc < (unsigned long) &__memcpy_end) ||
+		    (pc >= (unsigned long) &__bitops_begin &&
+		     pc < (unsigned long) &__bitops_end))
+			pc = o7;
+
+		pc -= (unsigned long) &_stext;
+		pc >>= prof_shift;
+
+		if(pc >= prof_len)
+			pc = prof_len - 1;
+		atomic_inc((atomic_t *)&prof_buffer[pc]);
+	}
+}
+
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	unsigned long ticks, pstate;
@@ -74,6 +102,10 @@
 	write_lock(&xtime_lock);
 
 	do {
+#ifndef __SMP__
+		if ((regs->tstate & TSTATE_PRIV) != 0)
+			sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
+#endif
 		do_timer(regs);
 
 		/* Guarentee that the following sequences execute
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile
--- v2.3.99-pre5/linux/arch/sparc64/lib/Makefile	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/lib/Makefile	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.21 2000/03/27 10:38:41 davem Exp $
+# $Id: Makefile,v 1.22 2000/03/31 04:06:23 davem Exp $
 # Makefile for Sparc library files..
 #
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.3.99-pre5/linux/arch/sparc64/lib/blockops.S	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/lib/blockops.S	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.24 2000/03/27 10:38:41 davem Exp $
+/* $Id: blockops.S,v 1.25 2000/04/13 04:45:58 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
@@ -26,9 +26,9 @@
 	.text
 
 	.align		32
-	.globl		copy_page
-	.type		copy_page,@function
-copy_page: /* %o0=dest, %o1=src */
+	.globl		_copy_page
+	.type		_copy_page,@function
+_copy_page: /* %o0=dest, %o1=src */
 	VISEntry
 	membar		#LoadStore | #StoreStore | #StoreLoad
 	ldda		[%o1] ASI_BLK_P, %f0
@@ -205,9 +205,9 @@
 	 stda		%f16, [%o0] ASI_BLK_COMMIT_P
 
 	.align		32
-	.globl		clear_page
-	.type		clear_page,@function
-clear_page:	/* %o0=dest */
+	.globl		_clear_page
+	.type		_clear_page,@function
+_clear_page:	/* %o0=dest */
 	VISEntryHalf
 	ba,pt		%xcc, clear_page_common
 	 clr		%o4
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/mm/Makefile linux/arch/sparc64/mm/Makefile
--- v2.3.99-pre5/linux/arch/sparc64/mm/Makefile	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/mm/Makefile	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.6 2000/01/31 01:30:49 davem Exp $
+# $Id: Makefile,v 1.7 2000/03/31 04:06:24 davem Exp $
 # Makefile for the linux Sparc64-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.3.99-pre5/linux/arch/sparc64/mm/fault.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/mm/fault.c	Tue Apr 25 17:52:01 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.45 2000/03/27 10:38:51 davem Exp $
+/* $Id: fault.c,v 1.47 2000/04/25 04:13:25 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -110,7 +110,8 @@
 	if(!pte_present(pte))
 		goto out;
 
-	pa = (pte_pagenr(pte) << PAGE_SHIFT) + (tpc & ~PAGE_MASK);
+	pa  = phys_base + (pte_pagenr(pte) << PAGE_SHIFT);
+	pa += (tpc & ~PAGE_MASK);
 
 	/* Use phys bypass so we don't pollute dtlb/dcache. */
 	__asm__ __volatile__("lduwa [%1] %2, %0"
@@ -295,7 +296,7 @@
 	}
 
 	{
-		int fault = handle_mm_fault(current, vma,
+		int fault = handle_mm_fault(mm, vma,
 					    address, (fault_code & FAULT_CODE_WRITE));
 
 		if (fault < 0)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.3.99-pre5/linux/arch/sparc64/mm/init.c	Sun Mar 19 18:35:30 2000
+++ linux/arch/sparc64/mm/init.c	Wed Apr 26 12:13:17 2000
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.149 2000/03/15 14:42:58 jj Exp $
+/*  $Id: init.c,v 1.151 2000/04/26 17:09:32 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -738,22 +738,17 @@
  */
 pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset, unsigned long color)
 {
-	unsigned long paddr = __get_free_pages(GFP_KERNEL, 1);
+	struct page *page = alloc_pages(GFP_KERNEL, 1);
 
-	if (paddr) {
-		struct page *page2 = mem_map + MAP_NR(paddr + PAGE_SIZE);
+	if (page) {
 		unsigned long *to_free;
+		unsigned long paddr;
 		pte_t *pte;
 
-		/* Set count of second page, so we can free it
-		 * seperately later on.
-		 */
-		atomic_set(&page2->count, 1);
-
-		/* Clear out both pages now. */
+		set_page_count((page + 1), 1);
+		paddr = page_address(page);
 		memset((char *)paddr, 0, (PAGE_SIZE << 1));
 
-		/* Determine which page we give to this request. */
 		if (!color) {
 			pte = (pte_t *) paddr;
 			to_free = (unsigned long *) (paddr + PAGE_SIZE);
@@ -804,50 +799,42 @@
         }
 }
 
-#undef DEBUG_BOOTMEM
-
 extern unsigned long cmdline_memory_size;
 
-unsigned long __init bootmem_init(void)
+unsigned long __init bootmem_init(unsigned long *pages_avail)
 {
 	unsigned long bootmap_size, start_pfn, end_pfn;
 	unsigned long end_of_phys_memory = 0UL;
-	unsigned long bootmap_pfn;
+	unsigned long bootmap_pfn, bytes_avail, size;
 	int i;
 
-	/* XXX It is a bit ambiguous here, whether we should
-	 * XXX treat the user specified mem=xxx as total wanted
-	 * XXX physical memory, or as a limit to the upper
-	 * XXX physical address we allow.  For now it is the
-	 * XXX latter. -DaveM
-	 */
-#ifdef DEBUG_BOOTMEM
-	prom_printf("bootmem_init: Scan sp_banks,  ");
-#endif
+
+	bytes_avail = 0UL;
 	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
 		end_of_phys_memory = sp_banks[i].base_addr +
 			sp_banks[i].num_bytes;
+		bytes_avail += sp_banks[i].num_bytes;
 		if (cmdline_memory_size) {
-			if (end_of_phys_memory > cmdline_memory_size) {
-				if (cmdline_memory_size < sp_banks[i].base_addr) {
-					end_of_phys_memory =
-						sp_banks[i-1].base_addr +
-						sp_banks[i-1].num_bytes;
+			if (bytes_avail > cmdline_memory_size) {
+				unsigned long slack = bytes_avail - cmdline_memory_size;
+
+				bytes_avail -= slack;
+				end_of_phys_memory -= slack;
+
+				sp_banks[i].num_bytes -= slack;
+				if (sp_banks[i].num_bytes == 0) {
 					sp_banks[i].base_addr = 0xdeadbeef;
-					sp_banks[i].num_bytes = 0;
 				} else {
-					sp_banks[i].num_bytes -=
-						(end_of_phys_memory -
-						 cmdline_memory_size);
-					end_of_phys_memory = cmdline_memory_size;
-					sp_banks[++i].base_addr = 0xdeadbeef;
-					sp_banks[i].num_bytes = 0;
+					sp_banks[i+1].num_bytes = 0;
+					sp_banks[i+1].base_addr = 0xdeadbeef;
 				}
 				break;
 			}
 		}
 	}
 
+	*pages_avail = bytes_avail >> PAGE_SHIFT;
+
 	/* Start with page aligned address of last symbol in kernel
 	 * image.  The kernel is hard mapped below PAGE_OFFSET in a
 	 * 4MB locked TLB translation.
@@ -886,50 +873,40 @@
 	}
 #endif	
 	/* Initialize the boot-time allocator. */
-#ifdef DEBUG_BOOTMEM
-	prom_printf("init_bootmem(spfn[%lx],bpfn[%lx],epfn[%lx])\n",
-		    start_pfn, bootmap_pfn, end_pfn);
-#endif
-	bootmap_size = init_bootmem(bootmap_pfn, end_pfn);
+	bootmap_size = init_bootmem_node(0, bootmap_pfn, phys_base>>PAGE_SHIFT, end_pfn);
 
 	/* Now register the available physical memory with the
 	 * allocator.
 	 */
-	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
-#ifdef DEBUG_BOOTMEM
-		prom_printf("free_bootmem: base[%lx] size[%lx]\n",
-			    sp_banks[i].base_addr,
-			    sp_banks[i].num_bytes);
-#endif
+	for (i = 0; sp_banks[i].num_bytes != 0; i++)
 		free_bootmem(sp_banks[i].base_addr,
 			     sp_banks[i].num_bytes);
-	}
 
-	/* Reserve the kernel text/data/bss, the bootmem bootmap and initrd. */
-#ifdef DEBUG_BOOTMEM
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start)
-		prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
-			    initrd_start, initrd_end - initrd_start);
-#endif		
-	prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
-		    phys_base, (start_pfn << PAGE_SHIFT) - phys_base);
-	prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
-		    (bootmap_pfn << PAGE_SHIFT), bootmap_size);
-#endif
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start) {
-		reserve_bootmem(initrd_start, initrd_end - initrd_start);
+		size = initrd_end - initrd_start;
+
+		/* Resert the initrd image area. */
+		reserve_bootmem(initrd_start, size);
+		*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
+
 		initrd_start += PAGE_OFFSET;
 		initrd_end += PAGE_OFFSET;
 	}
 #endif
-	reserve_bootmem(phys_base, (start_pfn << PAGE_SHIFT) - phys_base);
-	reserve_bootmem((bootmap_pfn << PAGE_SHIFT), bootmap_size);
+	/* Reserve the kernel text/data/bss. */
+	size = (start_pfn << PAGE_SHIFT) - phys_base;
+	reserve_bootmem(phys_base, size);
+	*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+	/* Reserve the bootmem map.   We do not account for it
+	 * in pages_avail because we will release that memory
+	 * in free_all_bootmem.
+	 */
+	size = bootmap_size;
+	reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
+	*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
-#ifdef DEBUG_BOOTMEM
-	prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn);
-#endif
 	return end_pfn;
 }
 
@@ -946,7 +923,7 @@
 	extern unsigned int sparc64_vpte_patchme2[1];
 	unsigned long alias_base = phys_base + PAGE_OFFSET;
 	unsigned long second_alias_page = 0;
-	unsigned long pt, flags, end_pfn;
+	unsigned long pt, flags, end_pfn, pages_avail;
 	unsigned long shift = alias_base - ((unsigned long)&empty_zero_page);
 
 	set_bit(0, mmu_context_bmap);
@@ -1001,7 +978,8 @@
 	flushi((long)&sparc64_vpte_patchme1[0]);
 	
 	/* Setup bootmem... */
-	last_valid_pfn = end_pfn = bootmem_init();
+	pages_avail = 0;
+	last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
 
 #ifdef CONFIG_SUN_SERIAL
 	/* This does not logically belong here, but we need to
@@ -1039,10 +1017,20 @@
 	flush_tlb_all();
 
 	{
-		unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0};
+		unsigned long zones_size[MAX_NR_ZONES];
+		unsigned long zholes_size[MAX_NR_ZONES];
+		unsigned long npages;
+		int znum;
+
+		for (znum = 0; znum < MAX_NR_ZONES; znum++)
+			zones_size[znum] = zholes_size[znum] = 0;
+
+		npages = end_pfn - (phys_base >> PAGE_SHIFT);
+		zones_size[ZONE_DMA] = npages;
+		zholes_size[ZONE_DMA] = npages - pages_avail;
 
-		zones_size[ZONE_DMA] = end_pfn;
-		free_area_init(zones_size);
+		free_area_init_node(0, NULL, zones_size,
+				    phys_base, zholes_size);
 	}
 
 	device_scan();
@@ -1139,9 +1127,6 @@
 	struct sparc_phys_banks saved_sp_banks[SPARC_PHYS_BANKS];
 	int i;
 
-#ifdef DEBUG_BOOTMEM
-	prom_printf("taint_real_pages: Rescan sp_banks[].\n");
-#endif
 	for (i = 0; i < SPARC_PHYS_BANKS; i++) {
 		saved_sp_banks[i].base_addr =
 			sp_banks[i].base_addr;
@@ -1176,10 +1161,6 @@
 					goto do_next_page;
 				}
 			}
-#ifdef DEBUG_BOOTMEM
-			prom_printf("taint: Page went away, reserve page %lx.\n",
-				    old_start);
-#endif
 			reserve_bootmem(old_start, PAGE_SIZE);
 
 		do_next_page:
@@ -1188,70 +1169,6 @@
 	}
 }
 
-void __init free_mem_map_range(struct page *first, struct page *last)
-{
-	first = (struct page *) PAGE_ALIGN((unsigned long)first);
-	last  = (struct page *) ((unsigned long)last & PAGE_MASK);
-#ifdef DEBUG_BOOTMEM
-	prom_printf("[%p,%p] ", first, last);
-#endif
-	while (first < last) {
-		ClearPageReserved(mem_map + MAP_NR(first));
-		set_page_count(mem_map + MAP_NR(first), 1);
-		free_page((unsigned long)first);
-		num_physpages++;
-
-		first = (struct page *)((unsigned long)first + PAGE_SIZE);
-	}
-}
-
-/* Walk through holes in sp_banks regions, if the mem_map array
- * areas representing those holes consume a page or more, free
- * up such pages.  This helps a lot on machines where physical
- * ram is configured such that it begins at some hugh value.
- *
- * The sp_banks array is sorted by base address.
- */
-void __init free_unused_mem_map(void)
-{
-	int i;
-
-#ifdef DEBUG_BOOTMEM
-	prom_printf("free_unused_mem_map: ");
-#endif
-	for (i = 0; sp_banks[i].num_bytes; i++) {
-		if (i == 0) {
-			struct page *first, *last;
-
-			first = mem_map;
-			last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
-			free_mem_map_range(first, last);
-		} else {
-			struct page *first, *last;
-			unsigned long prev_end;
-
-			prev_end = sp_banks[i-1].base_addr +
-				sp_banks[i-1].num_bytes;
-			prev_end = PAGE_ALIGN(prev_end);
-			first = &mem_map[prev_end >> PAGE_SHIFT];
-			last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
-
-			free_mem_map_range(first, last);
-
-			if (!sp_banks[i+1].num_bytes) {
-				prev_end = sp_banks[i].base_addr +
-					sp_banks[i].num_bytes;
-				first = &mem_map[prev_end >> PAGE_SHIFT];
-				last = &mem_map[last_valid_pfn];
-				free_mem_map_range(first, last);
-			}
-		}
-	}
-#ifdef DEBUG_BOOTMEM
-	prom_printf("\n");
-#endif
-}
-
 void __init mem_init(void)
 {
 	unsigned long codepages, datapages, initpages;
@@ -1279,16 +1196,10 @@
 
 	taint_real_pages();
 
-	max_mapnr = last_valid_pfn;
+	max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT);
 	high_memory = __va(last_valid_pfn << PAGE_SHIFT);
 
-#ifdef DEBUG_BOOTMEM
-	prom_printf("mem_init: Calling free_all_bootmem().\n");
-#endif
 	num_physpages = free_all_bootmem();
-#if 0
-	free_unused_mem_map();
-#endif
 	codepages = (((unsigned long) &etext) - ((unsigned long)&_start));
 	codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
 	datapages = (((unsigned long) &edata) - ((unsigned long)&etext));
@@ -1317,19 +1228,6 @@
 	       datapages << (PAGE_SHIFT-10), 
 	       initpages << (PAGE_SHIFT-10), 
 	       PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
-
-	/* NOTE NOTE NOTE NOTE
-	 * Please keep track of things and make sure this
-	 * always matches the code in mm/page_alloc.c -DaveM
-	 */
-	i = nr_free_pages() >> 7;
-	if (i < 48)
-		i = 48;
-	if (i > 256)
-		i = 256;
-	freepages.min = i;
-	freepages.low = i << 1;
-	freepages.high = freepages.low + i;
 }
 
 void free_initmem (void)
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/prom/Makefile linux/arch/sparc64/prom/Makefile
--- v2.3.99-pre5/linux/arch/sparc64/prom/Makefile	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/prom/Makefile	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 1999/12/21 04:02:26 davem Exp $
+# $Id: Makefile,v 1.6 2000/03/31 04:06:25 davem Exp $
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c
--- v2.3.99-pre5/linux/arch/sparc64/prom/misc.c	Wed Dec 29 13:13:15 1999
+++ linux/arch/sparc64/prom/misc.c	Mon Apr 24 13:59:58 2000
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.16 1999/11/19 05:53:04 davem Exp $
+/* $Id: misc.c,v 1.17 2000/04/15 06:02:50 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -64,7 +64,7 @@
 	 * on SMP, we need to drop the IRQ locks we hold.
 	 */
 #ifdef __SMP__
-	hardirq_exit(smp_processor_id());
+	irq_exit(smp_processor_id(), 0);
 	smp_capture();
 #else
 	local_irq_count--;
@@ -74,8 +74,8 @@
 
 #ifdef __SMP__
 	smp_release();
-	hardirq_enter(smp_processor_id());
-	spin_unlock_wait(&global_irq_lock);
+	irq_enter(smp_processor_id(), 0);
+	spin_unlock_wait(&__br_write_locks[BR_GLOBALIRQ_LOCK].lock);
 #else
 	local_irq_count++;
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- v2.3.99-pre5/linux/arch/sparc64/solaris/fs.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/solaris/fs.c	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.17 2000/03/10 04:43:30 davem Exp $
+/* $Id: fs.c,v 1.18 2000/04/08 02:11:54 davem Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -506,7 +506,7 @@
 		unlock_kernel();
 		fput(file);
 	}
-out:
+
 	return error;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.3.99-pre5/linux/arch/sparc64/solaris/misc.c	Tue Apr 11 15:09:15 2000
+++ linux/arch/sparc64/solaris/misc.c	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.23 2000/03/13 21:57:34 davem Exp $
+/* $Id: misc.c,v 1.26 2000/04/14 09:59:02 davem Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -54,7 +54,8 @@
 	unsigned long retval, ret_type;
 
 	lock_kernel();
-	current->personality |= PER_SVR4;
+	/* Do we need it here? */
+	set_personality(PER_SVR4);
 	if (flags & MAP_NORESERVE) {
 		static int cnt = 0;
 		
@@ -719,11 +720,7 @@
 
 asmlinkage void solaris_register(void)
 {
-	lock_kernel();
-	current->personality = PER_SVR4;
-	put_exec_domain(current->exec_domain);
-	current->exec_domain = lookup_exec_domain(current->personality);
-	unlock_kernel();
+	set_personality(PER_SVR4);
 }
 
 extern long solaris_to_linux_signals[], linux_to_solaris_signals[];
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c
--- v2.3.99-pre5/linux/drivers/acorn/net/ether1.c	Sun Feb 20 21:12:38 2000
+++ linux/drivers/acorn/net/ether1.c	Tue Apr 25 16:54:37 2000
@@ -798,6 +798,8 @@
 
 		if (ether1_init_for_open(dev))
 			printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
+		else
+			priv->restart = 0;
 	}
 
 	/*
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c
--- v2.3.99-pre5/linux/drivers/acorn/scsi/fas216.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/acorn/scsi/fas216.c	Tue Apr 25 16:54:37 2000
@@ -1415,6 +1415,7 @@
 	case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
 	case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
 		fas216_stoptransfer(info);
+	case STATE(STAT_MESGIN, PHASE_COMMAND):	/* Command	-> Message In	*/
 	case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
 	case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
 		info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
@@ -1753,6 +1754,23 @@
 	fas216_set_sync(info, SCpnt->target);
 
 	tot_msglen = msgqueue_msglength(&info->scsi.msgs);
+
+#ifdef DEBUG_MESSAGES
+	{
+		struct message *msg;
+		int msgnr = 0, i;
+
+		printk("scsi%d.%c: message out: ",
+			info->host->host_no, '0' + SCpnt->target);
+		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+			printk("{ ");
+			for (i = 0; i < msg->length; i++)
+				printk("%02x ", msg->msg[i]);
+			printk("} ");
+		}
+		printk("\n");
+	}
+#endif
 
 	if (tot_msglen == 1 || tot_msglen == 3) {
 		/*
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/Config.in linux/drivers/atm/Config.in
--- v2.3.99-pre5/linux/drivers/atm/Config.in	Sat Feb 26 22:31:42 2000
+++ linux/drivers/atm/Config.in	Fri Apr 14 09:37:10 2000
@@ -52,8 +52,8 @@
     fi
 fi
 if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then
-  tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E
-  if [ "$CONFIG_ATM_FORE200E" != "n" ]; then
+  tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E_MAYBE
+  if [ "$CONFIG_ATM_FORE200E_MAYBE" != "n" ]; then
     if [ "$CONFIG_PCI" = "y" ]; then
       bool '  PCA-200E support' CONFIG_ATM_FORE200E_PCA y
       if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then
@@ -72,8 +72,16 @@
         fi
       fi
     fi
+  fi
+  if [ "$CONFIG_ATM_FORE200E_PCA" = "y" -o "$CONFIG_ATM_FORE200E_SBA" = "y" ]; \
+    then
     int  '  Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16
     int  '  Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0
+    if [ "$CONFIG_ATM_FORE200E_MAYBE" = "y" ]; then
+      define_tristate CONFIG_ATM_FORE200E y
+    else
+      define_tristate CONFIG_ATM_FORE200E m
+    fi
   fi
 fi
 endmenu
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/Makefile linux/drivers/atm/Makefile
--- v2.3.99-pre5/linux/drivers/atm/Makefile	Mon Mar 27 08:08:22 2000
+++ linux/drivers/atm/Makefile	Fri Apr 14 09:37:10 2000
@@ -30,10 +30,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_ATM_TNETA1570),y)
-O_OBJS += tneta1570.o suni.o
-endif
-
 ifeq ($(CONFIG_ATM_NICSTAR),y)
 O_OBJS += nicstar.o
   ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
@@ -101,23 +97,29 @@
 endif
 
 ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
-FORE200E_FW_OBJS += fore200e_pca_fw.o
+  FORE200E_FW_OBJS += fore200e_pca_fw.o
+  ifeq ($(strip $(CONFIG_ATM_FORE200E_PCA_FW)),"")
+    CONFIG_ATM_FORE200E_PCA_DEFAULT_FW := y
+  endif
   ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
 #   guess the target endianess to choose the right PCA-200E firmware image
     CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi)
   endif
 endif
 ifeq ($(CONFIG_ATM_FORE200E_SBA),y)
-FORE200E_FW_OBJS += fore200e_sba_fw.o
+  FORE200E_FW_OBJS += fore200e_sba_fw.o
+  ifeq ($(strip $(CONFIG_ATM_FORE200E_SBA_FW)),"")
+    CONFIG_ATM_FORE200E_SBA_DEFAULT_FW := y
+  endif
   ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y)
     CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2
   endif
 endif
 ifeq ($(CONFIG_ATM_FORE200E),y)
-O_OBJS += fore200e.o $(FORE200E_FW_OBJS)
+  O_OBJS += fore200e.o $(FORE200E_FW_OBJS)
 else
   ifeq ($(CONFIG_ATM_FORE200E),m)
-  M_OBJS += fore_200e.o
+    M_OBJS += fore_200e.o
   endif
 endif
 
@@ -125,33 +127,51 @@
 
 include $(TOPDIR)/Rules.make
 
+
 # FORE Systems 200E-series firmware magic
 fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \
 	  fore200e_mkfirm
 	./fore200e_mkfirm -k -b _fore200e_pca_fw \
 	  -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@
+	@ ( \
+	  echo 'ifeq ($(strip $(CONFIG_ATM_FORE200E_PCA_FW)), $$(CONFIG_ATM_FORE200E_PCA_FW))'; \
+	  echo 'FORE200E_FW_UP_TO_DATE += $@'; \
+	  echo 'endif' \
+	) >.$@.fw
 
 fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \
 	  fore200e_mkfirm
 	./fore200e_mkfirm -k -b _fore200e_sba_fw \
 	  -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@
+	@ ( \
+	  echo 'ifeq ($(strip $(CONFIG_ATM_FORE200E_SBA_FW)), $$(CONFIG_ATM_FORE200E_SBA_FW))'; \
+	  echo 'FORE200E_FW_UP_TO_DATE += $@'; \
+	  echo 'endif' \
+	) >.$@.fw
 
 fore200e_mkfirm: fore200e_mkfirm.c
 	$(HOSTCC) $(HOSTCFLAGS) $< -o $@
 
-# deal with the various suffixes of the firmware images
-%.bin:  %.data
-	objcopy -Iihex $< -Obinary $@.gz
-	gzip -df $@.gz
-
-%.bin1: %.data
-	objcopy -Iihex $< -Obinary $@.gz
-	gzip -df $@.gz
-
-%.bin2: %.data
+# deal with the various suffixes of the binary firmware images
+%.bin %.bin1 %.bin2: %.data
 	objcopy -Iihex $< -Obinary $@.gz
 	gzip -df $@.gz
 
 # module build
 fore_200e.o: fore200e.o $(FORE200E_FW_OBJS)
 	$(LD) -r -o $@ $< $(FORE200E_FW_OBJS)
+
+# firmware dependency stuff taken from drivers/sound/Makefile
+FORE200E_FW_UP_TO_DATE :=
+
+FORE200E_FW_FILES := $(wildcard .fore200e_*.fw)
+ifneq ($(FORE200E_FW_FILES),)
+include $(FORE200E_FW_FILES)
+endif
+
+FORE200E_FW_CHANGED := $(filter-out $(FORE200E_FW_UP_TO_DATE), \
+                       fore200e_pca_fw.c fore200e_sba_fw.c)
+
+ifneq ($(FORE200E_FW_CHANGED),)
+$(FORE200E_FW_CHANGED): dummy
+endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c
--- v2.3.99-pre5/linux/drivers/atm/ambassador.c	Mon Mar 27 08:08:22 2000
+++ linux/drivers/atm/ambassador.c	Fri Apr 14 09:37:10 2000
@@ -1251,10 +1251,15 @@
     }
   }
   
+  // prevent module unload while sleeping (kmalloc/down)
+  // doing this any earlier would complicate more error return paths
+  MOD_INC_USE_COUNT;
+  
   // get space for our vcc stuff
   vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
   if (!vcc) {
     PRINTK (KERN_ERR, "out of memory!");
+    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   atm_vcc->dev_data = (void *) vcc;
@@ -1340,7 +1345,6 @@
   // indicate readiness
   set_bit(ATM_VF_READY,&atm_vcc->flags);
   
-  MOD_INC_USE_COUNT;
   return 0;
 }
 
@@ -1420,7 +1424,9 @@
   
   // say the VPI/VCI is free again
   clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
+
   MOD_DEC_USE_COUNT;
+  return;
 }
 
 /********** DebugIoctl **********/
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/ambassador.h linux/drivers/atm/ambassador.h
--- v2.3.99-pre5/linux/drivers/atm/ambassador.h	Mon Mar 27 08:08:22 2000
+++ linux/drivers/atm/ambassador.h	Fri Apr 14 09:37:10 2000
@@ -631,7 +631,7 @@
   u32              iobase;
   u32 *            membase;
 
-#if 0  
+#ifdef FILL_RX_POOLS_IN_BH
   struct tq_struct bh;
 #endif
   
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c
--- v2.3.99-pre5/linux/drivers/atm/atmdev_init.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/atmdev_init.c	Fri Apr 14 09:37:10 2000
@@ -1,21 +1,15 @@
 /* drivers/atm/atmdev_init.c - ATM device driver initialization */
  
-/* Written 1995-1997 by Werner Almesberger, EPFL LRC */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
  
 
 #include <linux/config.h>
 #include <linux/init.h>
 
 
-#ifdef CONFIG_ATM_ENI
-extern int eni_detect(void);
-#endif
 #ifdef CONFIG_ATM_ZATM
 extern int zatm_detect(void);
 #endif
-#ifdef CONFIG_ATM_TNETA1570
-extern int tneta1570_detect(void);
-#endif
 #ifdef CONFIG_ATM_NICSTAR
 extern int nicstar_detect(void);
 #endif
@@ -33,19 +27,19 @@
 #endif
 
 
+/*
+ * For historical reasons, atmdev_init returns the number of devices found.
+ * Note that some detections may not go via atmdev_init (e.g. eni.c), so this
+ * number is meaningless.
+ */
+
 int __init atmdev_init(void)
 {
 	int devs;
 
 	devs = 0;
-#ifdef CONFIG_ATM_ENI
-//	devs += eni_detect();
-#endif
 #ifdef CONFIG_ATM_ZATM
 	devs += zatm_detect();
-#endif
-#ifdef CONFIG_ATM_TNETA1570
-	devs += tneta1570_detect();
 #endif
 #ifdef CONFIG_ATM_NICSTAR
 	devs += nicstar_detect();
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/eni.c linux/drivers/atm/eni.c
--- v2.3.99-pre5/linux/drivers/atm/eni.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/eni.c	Fri Apr 14 09:37:10 2000
@@ -879,14 +879,13 @@
 			set_current_state(TASK_UNINTERRUPTIBLE);
 		}
 		for (;;) {
-			unsigned long flags;
 			int at_end;
 			u32 tmp;
 
-			spin_lock_irqsave(&eni_dev->lock,flags);
+			tasklet_disable(&eni_dev->task);
 			tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ;
 			at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT;
-			spin_unlock_irqrestore(&eni_dev->lock,flags);
+			tasklet_enable(&eni_dev->task);
 			if (at_end) break;
 			EVENT("drain discard (host 0x%lx, nic 0x%lx)\n",
 			    eni_vcc->rx_pos,tmp);
@@ -972,8 +971,8 @@
 	}
 #ifdef CONFIG_ATM_ENI_BURST_TX_16W /* may work with some PCI chipsets ... */
 	if (words & ~15) {
-		DPRINTK("put_dma: %lx DMA: %d*16/%d words\n",paddr,words >> 4,
-		    words);
+		DPRINTK("put_dma: %lx DMA: %d*16/%d words\n",
+		    (unsigned long) paddr,words >> 4,words);
 		dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT)
 		    | (chan << MID_DMA_CHAN_SHIFT);
 		dma[(*j)++] = paddr;
@@ -994,8 +993,8 @@
 #endif
 #ifdef CONFIG_ATM_ENI_BURST_TX_4W /* probably useless if TX_8W or TX_16W */
 	if (words & ~3) {
-		DPRINTK("put_dma: %lx DMA: %d*4/%d words\n",paddr,words >> 2,
-		    words);
+		DPRINTK("put_dma: %lx DMA: %d*4/%d words\n",
+		    (unsigned long) paddr,words >> 2,words);
 		dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT)
 		    | (chan << MID_DMA_CHAN_SHIFT);
 		dma[(*j)++] = paddr;
@@ -1005,8 +1004,8 @@
 #endif
 #ifdef CONFIG_ATM_ENI_BURST_TX_2W /* probably useless if TX_4W, TX_8W, ... */
 	if (words & ~1) {
-		DPRINTK("put_dma: %lx DMA: %d*2/%d words\n",paddr,words >> 1,
-		    words);
+		DPRINTK("put_dma: %lx DMA: %d*2/%d words\n",
+		    (unsigned long) paddr,words >> 1,words);
 		dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT)
 		    | (chan << MID_DMA_CHAN_SHIFT);
 		dma[(*j)++] = paddr;
@@ -1188,7 +1187,7 @@
 		if (tx->send)
 			while ((skb = skb_dequeue(&tx->backlog))) {
 				res = do_tx(skb);
-				if (res == enq_ok) tx->backlog_len--;
+				if (res == enq_ok) atomic_dec(&tx->backlog_len);
 				else {
 					DPRINTK("re-queuing TX PDU\n");
 					skb_queue_head(&tx->backlog,skb);
@@ -1327,7 +1326,7 @@
 		tx->send = mem;
 		tx->words = size >> 2;
 		skb_queue_head_init(&tx->backlog);
-		tx->backlog_len = 0;
+		atomic_set(&tx->backlog_len,0);
 		for (order = 0; size > (1 << (order+10)); order++);
 		eni_out((order << MID_SIZE_SHIFT) |
 		    ((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)),
@@ -1399,12 +1398,11 @@
 	add_wait_queue(&eni_dev->tx_wait,&wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	for (;;) {
-		unsigned long flags;
 		int txing;
 
-		spin_lock_irqsave(&eni_dev->lock,flags);
+		tasklet_disable(&eni_dev->task);
 		txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing;
-		spin_unlock_irqrestore(&eni_dev->lock,flags);
+		tasklet_enable(&eni_dev->task);
 		if (!txing) break;
 		DPRINTK("%d TX left\n",eni_vcc->txing);
 		schedule();
@@ -1468,44 +1466,24 @@
 #endif
 
 
-static void misc_int(struct atm_dev *dev,unsigned long reason)
+static void bug_int(struct atm_dev *dev,unsigned long reason)
 {
 	struct eni_dev *eni_dev;
 
-	DPRINTK(">misc_int\n");
+	DPRINTK(">bug_int\n");
 	eni_dev = ENI_DEV(dev);
-	if (reason & MID_STAT_OVFL) {
-		EVENT("stat overflow\n",0,0);
-		eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH;
-	}
-	if (reason & MID_SUNI_INT) {
-		EVENT("SUNI int\n",0,0);
-		dev->phy->interrupt(dev);
-#if 0
-		foo();
-#endif
-	}
-	if (reason & MID_DMA_ERR_ACK) {
+	if (reason & MID_DMA_ERR_ACK)
 		printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA "
 		    "error\n",dev->number);
-		EVENT("---dump ends here---\n",0,0);
-		printk(KERN_NOTICE "---recent events---\n");
-		event_dump();
-	}
-	if (reason & MID_TX_IDENT_MISM) {
+	if (reason & MID_TX_IDENT_MISM)
 		printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - ident "
 		    "mismatch\n",dev->number);
-		EVENT("---dump ends here---\n",0,0);
-		printk(KERN_NOTICE "---recent events---\n");
-		event_dump();
-	}
-	if (reason & MID_TX_DMA_OVFL) {
+	if (reason & MID_TX_DMA_OVFL)
 		printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA "
 		    "overflow\n",dev->number);
-		EVENT("---dump ends here---\n",0,0);
-		printk(KERN_NOTICE "---recent events---\n");
-		event_dump();
-	}
+	EVENT("---dump ends here---\n",0,0);
+	printk(KERN_NOTICE "---recent events---\n");
+	event_dump();
 }
 
 
@@ -1513,54 +1491,78 @@
 {
 	struct atm_dev *dev;
 	struct eni_dev *eni_dev;
-	unsigned long reason;
+	u32 reason;
 
 	DPRINTK(">eni_int\n");
 	dev = dev_id;
 	eni_dev = ENI_DEV(dev);
-	while ((reason = eni_in(MID_ISA))) {
-		DPRINTK(DEV_LABEL ": int 0x%lx\n",reason);
-		if (reason & MID_RX_DMA_COMPLETE) {
-			EVENT("INT: RX DMA complete, starting dequeue_rx\n",
-			    0,0);
-			spin_lock(&eni_dev->lock);
-			dequeue_rx(dev);
-			EVENT("dequeue_rx done, starting poll_rx\n",0,0);
-			poll_rx(dev);
-			spin_unlock(&eni_dev->lock);
-			EVENT("poll_rx done\n",0,0);
-			/* poll_tx ? */
-		}
-		if (reason & MID_SERVICE) {
-			EVENT("INT: service, starting get_service\n",0,0);
-			spin_lock(&eni_dev->lock);
-			get_service(dev);
-			EVENT("get_service done, starting poll_rx\n",0,0);
-			poll_rx(dev);
-			spin_unlock(&eni_dev->lock);
-			EVENT("poll_rx done\n",0,0);
-		}
- 		if (reason & MID_TX_DMA_COMPLETE) {
-			EVENT("INT: TX DMA COMPLETE\n",0,0);
-			spin_lock(&eni_dev->lock);
-			dequeue_tx(dev);
-			spin_unlock(&eni_dev->lock);
-		}
-		if (reason & MID_TX_COMPLETE) {
-			EVENT("INT: TX COMPLETE\n",0,0);
+	reason = eni_in(MID_ISA);
+	DPRINTK(DEV_LABEL ": int 0x%lx\n",(unsigned long) reason);
+	/*
+	 * Must handle these two right now, because reading ISA doesn't clear
+	 * them, so they re-occur and we never make it to the tasklet. Since
+	 * they're rare, we don't mind the occasional invocation of eni_tasklet
+	 * with eni_dev->events == 0.
+	 */
+	if (reason & MID_STAT_OVFL) {
+		EVENT("stat overflow\n",0,0);
+		eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH;
+	}
+	if (reason & MID_SUNI_INT) {
+		EVENT("SUNI int\n",0,0);
+		dev->phy->interrupt(dev);
+#if 0
+		foo();
+#endif
+	}
+	spin_lock(&eni_dev->lock);
+	eni_dev->events |= reason;
+	spin_unlock(&eni_dev->lock);
+	tasklet_schedule(&eni_dev->task);
+}
+
+
+static void eni_tasklet(unsigned long data)
+{
+	struct atm_dev *dev = (struct atm_dev *) data;
+	struct eni_dev *eni_dev = ENI_DEV(dev);
+	unsigned long flags;
+	u32 events;
+
+	DPRINTK("eni_tasklet (dev %p)\n",dev);
+	spin_lock_irqsave(&eni_dev->lock,flags);
+	events = xchg(&eni_dev->events,0);
+	spin_unlock_irqrestore(&eni_dev->lock,flags);
+	if (events & MID_RX_DMA_COMPLETE) {
+		EVENT("INT: RX DMA complete, starting dequeue_rx\n",0,0);
+		dequeue_rx(dev);
+		EVENT("dequeue_rx done, starting poll_rx\n",0,0);
+		poll_rx(dev);
+		EVENT("poll_rx done\n",0,0);
+		/* poll_tx ? */
+	}
+	if (events & MID_SERVICE) {
+		EVENT("INT: service, starting get_service\n",0,0);
+		get_service(dev);
+		EVENT("get_service done, starting poll_rx\n",0,0);
+		poll_rx(dev);
+		EVENT("poll_rx done\n",0,0);
+	}
+ 	if (events & MID_TX_DMA_COMPLETE) {
+		EVENT("INT: TX DMA COMPLETE\n",0,0);
+		dequeue_tx(dev);
+	}
+	if (events & MID_TX_COMPLETE) {
+		EVENT("INT: TX COMPLETE\n",0,0);
 tx_complete++;
-			spin_lock(&eni_dev->lock);
-			poll_tx(dev);
-			spin_unlock(&eni_dev->lock);
-			wake_up(&eni_dev->tx_wait);
-			/* poll_rx ? */
-		}
-		if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK |
-		    MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) {
-			EVENT("misc interrupt\n",0,0);
-			misc_int(dev,reason);
-		}
+		wake_up(&eni_dev->tx_wait);
+		/* poll_rx ? */
+	}
+	if (events & (MID_DMA_ERR_ACK | MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) {
+		EVENT("bug interrupt\n",0,0);
+		bug_int(dev,events);
 	}
+	poll_tx(dev);
 }
 
 
@@ -1824,6 +1826,8 @@
 	     eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,
 	     eni_dev->service,buf);
 	spin_lock_init(&eni_dev->lock);
+	tasklet_init(&eni_dev->task,eni_tasklet,(unsigned long) dev);
+	eni_dev->events = 0;
 	/* initialize memory management */
 	buffer_mem = eni_dev->mem-(buf-eni_dev->ram);
 	eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2;
@@ -1969,7 +1973,6 @@
 	struct eni_dev *eni_dev = ENI_DEV(vcc->dev);
 	struct eni_tx *tx = ENI_VCC(vcc)->tx;
 	struct sk_buff *skb;
-	unsigned long flags;
 	int error,rate,rsv,shp;
 
 	if (qos->txtp.traffic_class == ATM_NONE) return 0;
@@ -1989,7 +1992,7 @@
 	 * Walk through the send buffer and patch the rate information in all
 	 * segmentation buffer descriptors of this VCC.
 	 */
-	spin_lock_irqsave(&eni_dev->lock,flags);
+	tasklet_disable(&eni_dev->task);
 	for (skb = eni_dev->tx_queue.next; skb !=
 	    (struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) {
 		unsigned long dsc;
@@ -2000,7 +2003,7 @@
 		    (tx->prescaler << MID_SEG_PR_SHIFT) |
 		    (tx->resolution << MID_SEG_RATE_SHIFT), dsc);
 	}
-	spin_unlock_irqrestore(&eni_dev->lock,flags);
+	tasklet_enable(&eni_dev->task);
 	return 0;
 }
 
@@ -2061,8 +2064,6 @@
 
 static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
-	unsigned long flags;
-
 	DPRINTK(">eni_send\n");
 	if (!ENI_VCC(vcc)->tx) {
 		if (vcc->pop) vcc->pop(vcc,skb);
@@ -2084,13 +2085,10 @@
 	}
 submitted++;
 	ATM_SKB(skb)->vcc = vcc;
-	spin_lock_irqsave(&ENI_DEV(vcc->dev)->lock,flags); /* brute force */
-	if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) {
-		skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb);
-		ENI_VCC(vcc)->tx->backlog_len++;
+	skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb);
+	atomic_inc(&ENI_VCC(vcc)->tx->backlog_len);
 backlogged++;
-	}
-	spin_unlock_irqrestore(&ENI_DEV(vcc->dev)->lock,flags);
+	tasklet_schedule(&ENI_DEV(vcc->dev)->task);
 	return 0;
 }
 
@@ -2189,7 +2187,7 @@
 		}
 		if (--left) continue;
 		return sprintf(page,"%10sbacklog %d bytes\n","",
-		    tx->backlog_len);
+		    atomic_read(&tx->backlog_len));
 	}
 	for (vcc = dev->vccs; vcc; vcc = vcc->next) {
 		struct eni_vcc *eni_vcc = ENI_VCC(vcc);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/eni.h linux/drivers/atm/eni.h
--- v2.3.99-pre5/linux/drivers/atm/eni.h	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/eni.h	Fri Apr 14 09:37:10 2000
@@ -13,6 +13,7 @@
 #include <linux/time.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <asm/atomic.h>
 
 #include "midway.h"
 
@@ -46,7 +47,7 @@
 	int reserved;			/* reserved peak cell rate */
 	int shaping;			/* shaped peak cell rate */
 	struct sk_buff_head backlog;	/* queue of waiting TX buffers */
-	int backlog_len;		/* length of backlog in bytes */
+	atomic_t backlog_len;		/* length of backlog in bytes */
 };
 
 struct eni_vcc {
@@ -68,6 +69,8 @@
 struct eni_dev {
 	/*-------------------------------- spinlock */
 	spinlock_t lock;		/* sync with interrupt */
+	struct tasklet_struct task;	/* tasklet for interrupt work */
+	u32 events;			/* pending events */
 	/*-------------------------------- base pointers into Midway address
 					   space */
 	unsigned long phy;		/* PHY interface chip registers */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c
--- v2.3.99-pre5/linux/drivers/atm/fore200e.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/atm/fore200e.c	Fri Apr 14 09:37:10 2000
@@ -1,8 +1,8 @@
 /*
-  $Id: fore200e.c,v 1.2 2000/03/21 21:19:24 davem Exp $
+  $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $
 
   A FORE Systems 200E-series driver for ATM on Linux.
-  Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000.
+  Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000.
 
   Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de).
 
@@ -32,10 +32,11 @@
 #include <linux/init.h>
 #include <linux/capability.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
 #include <linux/atmdev.h>
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
-#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/string.h>
 #include <asm/segment.h>
@@ -66,7 +67,7 @@
 #define FORE200E_52BYTE_AAL0_SDU
 #endif
 
-#define FORE200E_VERSION "0.2b"
+#define FORE200E_VERSION "0.2d"
 
 
 #define FORE200E         "fore200e: "
@@ -444,6 +445,7 @@
 }
 
 
+
 #ifdef CONFIG_ATM_FORE200E_PCA
 
 static u32 fore200e_pca_read(volatile u32* addr)
@@ -477,7 +479,8 @@
 static void
 fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+    DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n",
+	    dma_addr, size, direction);
 
     pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
 }
@@ -496,7 +499,8 @@
    (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
 
 static int
-fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment)
+fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
+			     int size, int nbr, int alignment)
 {
 #if defined(__sparc_v9__)
     /* returned chunks are page-aligned */
@@ -659,6 +663,7 @@
 
     sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
 
+    pci_enable_device(pci_dev);
     pci_set_master(pci_dev);
 
     return fore200e;
@@ -756,7 +761,8 @@
 static void
 fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction);
+    DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
+	    dma_addr, size, direction);
 
     sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
 }
@@ -775,7 +781,8 @@
    (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
 
 static int
-fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment)
+fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
+			     int size, int nbr, int alignment)
 {
     chunk->alloc_size = chunk->align_size = size * nbr;
 
@@ -1234,15 +1241,25 @@
     }
     DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]);
 
-    fore200e_irq_rx(fore200e);
+    tasklet_schedule(&fore200e->tasklet);
+    
+    fore200e->bus->irq_ack(fore200e);
+}
+
+
+static void
+fore200e_tasklet(unsigned long data)
+{
+    struct fore200e* fore200e = (struct fore200e*) data;
 
+    fore200e_irq_rx(fore200e);
+    
     if (fore200e->host_txq.txing)
 	fore200e_irq_tx(fore200e);
-    
-    fore200e->bus->irq_ack(fore200e);
 }
 
 
+
 static int
 fore200e_select_scheme(struct atm_vcc* vcc)
 {
@@ -1400,7 +1417,7 @@
     if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
 	return 0;
 
-    set_bit(ATM_VF_ADDR,&vcc->flags);
+    set_bit(ATM_VF_ADDR, &vcc->flags);
     vcc->itf    = vcc->dev->number;
 
     DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
@@ -1463,7 +1480,7 @@
     fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536;
     fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0;
     
-    clear_bit(ATM_VF_READY,&vcc->flags);
+    set_bit(ATM_VF_READY, &vcc->flags);
     return 0;
 }
 
@@ -1489,6 +1506,8 @@
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
     }
+
+    clear_bit(ATM_VF_READY, &vcc->flags);
 }
 
 
@@ -1506,7 +1525,7 @@
     struct host_txq_entry* entry;
     struct tpd*            tpd;
     struct tpd_haddr       tpd_haddr;
-    unsigned long          flags;
+    //unsigned long          flags;
     int                    retry        = CONFIG_ATM_FORE200E_TX_RETRY;
     int                    tx_copy      = 0;
     int                    tx_len       = skb->len;
@@ -1531,7 +1550,7 @@
     
   retry_here:
     
-    spin_lock_irqsave(&fore200e->tx_lock, flags);
+    tasklet_disable(&fore200e->tasklet);
 
     entry = &txq->host_entry[ txq->head ];
     
@@ -1542,7 +1561,7 @@
 	
 	if (*entry->status != STATUS_FREE) {
 	    
-	    spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+	    tasklet_enable(&fore200e->tasklet);
 
 	    /* retry once again? */
 	    if(--retry > 0)
@@ -1582,7 +1601,7 @@
 	entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
 	if (entry->data == NULL) {
 	    
-	    spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+	    tasklet_enable(&fore200e->tasklet);
 	    if (vcc->pop)
 		vcc->pop(vcc, skb);
 	    else
@@ -1606,10 +1625,10 @@
     FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX);
     txq->txing++;
 
-    spin_unlock_irqrestore(&fore200e->tx_lock, flags);
-    
+    tasklet_enable(&fore200e->tasklet);
+
     /* ensure DMA synchronisation */
-	fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
+    fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
     
     DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", 
 	    vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
@@ -1934,8 +1953,7 @@
 	return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0;
 
     case ATM_QUERYLOOP:
-	return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ?
-	    -EFAULT : 0;
+	return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? -EFAULT : 0;
     }
 
     return -ENOSYS; /* not implemented */
@@ -1976,7 +1994,7 @@
 	/* update rate control parameters */
 	fore200e_rate_ctrl(qos, &fore200e_vcc->rate);
 
-	set_bit(ATM_VF_HASQOS,&vcc->flags);
+	set_bit(ATM_VF_HASQOS, &vcc->flags);
 	return 0;
     }
     
@@ -1997,6 +2015,8 @@
     printk(FORE200E "IRQ %s reserved for device %s\n",
 	   fore200e_irq_itoa(fore200e->irq), fore200e->name);
 
+    tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e);
+
     fore200e->state = FORE200E_STATE_IRQ;
     return 0;
 }
@@ -2338,7 +2358,6 @@
 
     DPRINTK(2, "device %s being initialized\n", fore200e->name);
 
-    spin_lock_init(&fore200e->tx_lock);
     init_MUTEX(&fore200e->rate_sf);
     
     cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET);
@@ -2714,7 +2733,7 @@
 	if (media_index < 0 || media_index > 4)
 	    media_index = 5;
 	
-	switch(fore200e->loop_mode) {
+	switch (fore200e->loop_mode) {
 	    case ATM_LM_NONE:    oc3_index = 0;
 		                 break;
 	    case ATM_LM_LOC_PHY: oc3_index = 1;
@@ -2900,21 +2919,24 @@
 
 
 #ifdef MODULE
-unsigned int
-init_module(void)
+static unsigned int __init
+fore200e_module_init(void)
 {
     DPRINTK(1, "module loaded\n");
     return fore200e_detect() == 0;
 }
 
-void
-cleanup_module(void)
+static void __exit
+fore200e_module_cleanup(void)
 {
     while (fore200e_boards) {
 	fore200e_cleanup(&fore200e_boards);
     }
     DPRINTK(1, "module being removed\n");
 }
+
+module_init(fore200e_module_init);
+module_exit(fore200e_module_cleanup);
 #endif
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/fore200e.h linux/drivers/atm/fore200e.h
--- v2.3.99-pre5/linux/drivers/atm/fore200e.h	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/fore200e.h	Fri Apr 14 09:37:10 2000
@@ -1,3 +1,4 @@
+/* $Id: fore200e.h,v 1.4 2000/04/14 10:10:34 davem Exp $ */
 #ifndef _FORE200E_H
 #define _FORE200E_H
 
@@ -827,14 +828,18 @@
 #    else
        /* in that case, we'll need to add an extra indirection, e.g.
 	  fore200e->bus->dma_direction[ fore200e_dma_direction ] */
-#      error PCI and SBUS DMA direction flags differ!
+#      error PCI and SBUS DMA direction flags have different values!
 #    endif
 #  else
-#    define FORE200E_DMA_BIDIRECTIONAL SBA_DMA_BIDIRECTIONAL
-#    define FORE200E_DMA_TODEVICE      SBA_DMA_TODEVICE
-#    define FORE200E_DMA_FROMDEVICE    SBA_DMA_FROMDEVICE
+#    define FORE200E_DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL
+#    define FORE200E_DMA_TODEVICE      SBUS_DMA_TODEVICE
+#    define FORE200E_DMA_FROMDEVICE    SBUS_DMA_FROMDEVICE
 #  endif
 #else
+#  ifndef CONFIG_ATM_FORE200E_PCA
+#    warning compiling the fore200e driver without any hardware support enabled!
+#    include <linux/pci.h>
+#  endif
 #  define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
 #  define FORE200E_DMA_TODEVICE      PCI_DMA_TODEVICE
 #  define FORE200E_DMA_FROMDEVICE    PCI_DMA_FROMDEVICE
@@ -874,7 +879,7 @@
     struct stats*              stats;                  /* last snapshot of the stats         */
     
     struct semaphore           rate_sf;                /* protects rate reservation ops      */
-    spinlock_t                 tx_lock;                /* protects tx ops                    */
+    struct tasklet_struct      tasklet;                /* performs interrupt work            */
 
 } fore200e_t;
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c
--- v2.3.99-pre5/linux/drivers/atm/horizon.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/horizon.c	Fri Apr 14 09:37:10 2000
@@ -2490,10 +2490,15 @@
     return -EINVAL;
   }
   
+  // prevent module unload while sleeping (kmalloc)
+  // doing this any earlier would complicate more error return paths
+  MOD_INC_USE_COUNT;
+  
   // get space for our vcc stuff and copy parameters into it
   vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL);
   if (!vccp) {
     PRINTK (KERN_ERR, "out of memory!");
+    MOD_DEC_USE_COUNT;
     return -ENOMEM;
   }
   *vccp = vcc;
@@ -2525,6 +2530,7 @@
   if (error) {
     PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources");
     kfree (vccp);
+    MOD_DEC_USE_COUNT;
     return error;
   }
   
@@ -2537,11 +2543,13 @@
   if (rxtp->traffic_class != ATM_NONE) {
     if (dev->rxer[channel]) {
       PRINTD (DBG_ERR|DBG_VCC, "VC already open for RX");
-      return -EBUSY;
+      error = -EBUSY;
     }
-    error = hrz_open_rx (dev, channel);
+    if (!error)
+      error = hrz_open_rx (dev, channel);
     if (error) {
       kfree (vccp);
+      MOD_DEC_USE_COUNT;
       return error;
     }
     // this link allows RX frames through
@@ -2556,7 +2564,6 @@
   // indicate readiness
   set_bit(ATM_VF_READY,&atm_vcc->flags);
   
-  MOD_INC_USE_COUNT;
   return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c
--- v2.3.99-pre5/linux/drivers/atm/uPD98402.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/atm/uPD98402.c	Fri Apr 14 09:37:10 2000
@@ -141,7 +141,7 @@
 			return fetch_stats(dev,(struct sonet_stats *) arg,
 			    cmd == SONET_GETSTATZ);
 		case SONET_SETFRAMING:
-			return set_framing(dev,(int) arg);
+			return set_framing(dev,(int) (long) arg);
 		case SONET_GETFRAMING:
 			return put_user(PRIV(dev)->framing,(int *) arg) ?
 			    -EFAULT : 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.99-pre5/linux/drivers/block/Config.in	Tue Apr 11 15:09:16 2000
+++ linux/drivers/block/Config.in	Wed Apr 12 09:38:52 2000
@@ -41,14 +41,16 @@
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
 
+tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM N
+if [ "$CONFIG_BLK_DEV_LVM" != "n" ]; then
+   bool '   LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y
+fi
+
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 dep_tristate '  Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD
 dep_tristate '  RAID-0 (striping) mode' CONFIG_MD_STRIPED $CONFIG_BLK_DEV_MD
 #dep_tristate '  RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING $CONFIG_BLK_DEV_MD
 #dep_tristate '  RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD
-if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
-fi
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.99-pre5/linux/drivers/block/floppy.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/block/floppy.c	Mon Apr 24 18:17:45 2000
@@ -201,7 +201,7 @@
 static unsigned short virtual_dma_port=0x3f0;
 void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static int set_dor(int fdc, char mask, char data);
-static void register_devfs_entries (int drive);
+static void register_devfs_entries (int drive) __init;
 static devfs_handle_t devfs_handle = NULL;
 
 #define K_64	0x10000		/* 64KB */
@@ -3582,7 +3582,7 @@
 #undef IN
 }
 
-static void config_types(void)
+static void __init config_types(void)
 {
 	int first=1;
 	int drive;
@@ -3836,7 +3836,7 @@
 	revalidate:		floppy_revalidate,
 };
 
-static void register_devfs_entries (int drive)
+static void __init register_devfs_entries (int drive)
 {
     int base_minor, i;
     static char *table[] =
@@ -4075,8 +4075,8 @@
 		printk("\n");
 	} else
 		DPRINT("botched floppy option\n");
-	DPRINT("Read linux/drivers/block/README.fd\n");
-	return 1;
+	DPRINT("Read linux/Documentation/floppy.txt\n");
+	return 0;
 }
 
 static int have_no_fdc= -EIO;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.3.99-pre5/linux/drivers/block/genhd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/genhd.c	Wed Apr 12 09:38:52 2000
@@ -37,16 +37,12 @@
 #ifdef CONFIG_PARPORT
 	parport_init();
 #endif
-	/*
-	 *	I2O must come before block and char as the I2O layer may
-	 *	in future claim devices that block/char most not touch.
-	 */
-#ifdef CONFIG_I2O
-	i2o_init();
-#endif
 	chr_dev_init();
 	blk_dev_init();
 	sti();
+#ifdef CONFIG_I2O
+	i2o_init();
+#endif
 #ifdef CONFIG_BLK_DEV_DAC960
 	DAC960_Initialize();
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.99-pre5/linux/drivers/block/ll_rw_blk.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/block/ll_rw_blk.c	Wed Apr 26 12:13:16 2000
@@ -1077,6 +1077,12 @@
 #ifdef CONFIG_DASD
 	dasd_init();
 #endif
+#ifdef CONFIG_SUN_JSFLASH
+	jsfd_init();
+#endif
+#ifdef CONFIG_BLK_DEV_LVM
+	lvm_init();
+#endif 
 	return 0;
 };
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/lvm.c linux/drivers/block/lvm.c
--- v2.3.99-pre5/linux/drivers/block/lvm.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/block/lvm.c	Wed Apr 12 09:38:52 2000
@@ -287,7 +287,7 @@
 static char pv_name[NAME_LEN];
 /* static char rootvg[NAME_LEN] = { 0, }; */
 static uint lv_open = 0;
-static const char *const lvm_name = LVM_NAME;
+const char *const lvm_name = LVM_NAME;
 static int lock = 0;
 static int loadtime = 0;
 static uint vg_count = 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.3.99-pre5/linux/drivers/block/md.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/block/md.c	Wed Apr 12 09:38:52 2000
@@ -46,10 +46,6 @@
 
 #include <linux/blk.h>
 
-#ifdef CONFIG_MD_BOOT
-extern kdev_t name_to_kdev_t(char *line) md__init;
-#endif
-
 #define DEBUG 0
 #if DEBUG
 # define dprintk(x...) printk(x)
@@ -1805,136 +1801,6 @@
 
 #undef OUT
 
-/* support old ioctls/init - cold add only */
-int do_md_add(mddev_t *mddev, kdev_t dev)
-{
-	int err;
-	mdk_rdev_t *rdev;
-	
-	if (mddev->sb || mddev->pers)
-		return -EBUSY;
-	err = md_import_device(dev, 0);
-	if (err) return err;
-	rdev = find_rdev_all(dev);
-	if (!rdev) {
-		MD_BUG();
-		return -EINVAL;
-	}
-	rdev->old_dev = dev;
-	rdev->desc_nr = mddev->nb_dev;
-	bind_rdev_to_array(rdev, mddev);
-	return 0;
-}
-
-#define SET_SB(x,v) mddev->sb->x = v
-#define SET_RSB(x,y) mddev->sb->disks[nr].x = y
-static void autorun_array (mddev_t *mddev);
-int do_md_start(mddev_t *mddev, int info)
-{
-	int pers = (info & 0xFF0000UL)>>16;
-//	int fault= (info & 0x00FF00UL)>>8;
-	int factor=(info & 0x0000FFUL);
-
-	struct md_list_head *tmp;
-	mdk_rdev_t *rdev, *rdev0=NULL;
-	int err = 0;
-
-	if (mddev->sb) {
-		printk("array md%d already has superbloc!!\n",
-		       mdidx(mddev));
-		return -EBUSY;
-	}
-	if (pers==1 || pers==2) {
-		/* non-persistant super block */
-		int devs = mddev->nb_dev;
-		if (alloc_array_sb(mddev))
-			return -ENOMEM;
-		mddev->sb->major_version = MD_MAJOR_VERSION;
-		mddev->sb->minor_version = MD_MINOR_VERSION;
-		mddev->sb->patch_version = MD_PATCHLEVEL_VERSION;
-		mddev->sb->ctime = CURRENT_TIME;
-
-		SET_SB(level,pers_to_level(pers));
-		SET_SB(size,0);
-		SET_SB(nr_disks, devs);
-		SET_SB(raid_disks, devs);
-		SET_SB(md_minor,mdidx(mddev));
-		SET_SB(not_persistent, 1);
-
-		
-		SET_SB(state, 1<<MD_SB_CLEAN);
-		SET_SB(active_disks, devs);
-		SET_SB(working_disks, devs);
-		SET_SB(failed_disks, 0);
-		SET_SB(spare_disks, 0);
-
-		SET_SB(layout,0);
-		SET_SB(chunk_size, 1<<(factor+PAGE_SHIFT));
-
-		mddev->sb->md_magic = MD_SB_MAGIC;
-
-		/*
-		 * Generate a 128 bit UUID
-		 */
-		get_random_bytes(&mddev->sb->set_uuid0, 4);
-		get_random_bytes(&mddev->sb->set_uuid1, 4);
-		get_random_bytes(&mddev->sb->set_uuid2, 4);
-		get_random_bytes(&mddev->sb->set_uuid3, 4);
-
-		/* add each disc */
-		ITERATE_RDEV(mddev,rdev,tmp) {
-			int nr, size;
-			nr = rdev->desc_nr;
-			SET_RSB(number,nr);
-			SET_RSB(major,MAJOR(rdev->dev));
-			SET_RSB(minor,MINOR(rdev->dev));
-			SET_RSB(raid_disk,nr);
-			SET_RSB(state,6); /* ACTIVE|SYNC */
-			size = calc_dev_size(rdev->dev, mddev, 0);
-			rdev->sb_offset = calc_dev_sboffset(rdev->dev, mddev, 0);
-
-			if (!mddev->sb->size || (mddev->sb->size > size))
-				mddev->sb->size = size;			
-		}
-		sync_sbs(mddev);
-		err = do_md_run(mddev);
-		if (err)
-			do_md_stop(mddev, 0);
-	} else {
-		/* persistant super block - ignore the info and read the superblocks */
-		ITERATE_RDEV(mddev,rdev,tmp) {
-			if ((err = read_disk_sb(rdev))) {
-				printk("md: could not read %s's sb, not importing!\n",
-				       partition_name(rdev->dev));
-				break;
-			}
-			if ((err = check_disk_sb(rdev))) {
-				printk("md: %s has invalid sb, not importing!\n",
-				       partition_name(rdev->dev));
-				break;
-			}
-			rdev->desc_nr = rdev->sb->this_disk.number;
-			if (!rdev0) rdev0=rdev;
-			if (!uuid_equal(rdev0, rdev)) {
-				printk("%s has different UUID to %s .. dropping\n",
-				       partition_name(rdev->dev),
-				       partition_name(rdev0->dev));
-				err = -EINVAL;
-				break;
-			}
-			if (!sb_equal(rdev0->sb, rdev->sb)) {
-				printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev));
-				err = -EINVAL;
-				break;
-			}
-		}
-		if (!err)
-			autorun_array(mddev);
-	}
-	return err;
-}
-#undef SET_SB
-#undef SET_RSB
 /*
  * We have to safely support old arrays too.
  */
@@ -2703,59 +2569,6 @@
 			}
 		default:
 	}
-	/* handle "old style" ioctls */
-	switch (cmd)
-	{
-	case START_MD:
-		if (!mddev)
-			return -ENODEV;
-		err = lock_mddev(mddev);
-		if (err) {
-			printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
-			goto abort;
-		}
-		err = do_md_start(mddev, (int) arg);
-		if (err) {
-			printk("couldn't mdstart\n");
-			goto abort_unlock;
-		}
-		goto done_unlock;
-	case STOP_MD:
-		if (!mddev)
-			return -ENODEV;
-		err = lock_mddev(mddev);
-		if (err) {
-			printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
-			goto abort_unlock;
-		}
-		err =  do_md_stop(mddev, 0);
-		if (err) {
-			printk("couldn't mdstop\n");
-			goto abort_unlock;
-		}
-		goto done_unlock;
-	case REGISTER_DEV:
-		/* add this device to an unstarted array,
-		 * create the array if needed */
-		if (!mddev)
-			mddev = alloc_mddev(dev);
-		if (!mddev) {
-			err = -ENOMEM;
-			goto abort;
-		}
-		err = lock_mddev(mddev);
-		if (err) {
-			printk("ioctl, reason %d, cmd %d\n", err, cmd);
-			goto abort;
-		}
-		err = do_md_add(mddev, to_kdev_t((dev_t) arg));
-		if (err) {
-			printk("do_md_add failed %d\n", err);
-			goto abort_unlock;
-		}
-		goto done_unlock;
-	}
-
 	switch (cmd)
 	{
 		case SET_ARRAY_INFO:
@@ -3369,94 +3182,11 @@
 	return;
 }
 
-#ifdef CONFIG_MD_BOOT
-#define MAX_MD_BOOT_DEVS	16
-struct {
-	unsigned long set;
-	int pers[MAX_MD_BOOT_DEVS];
-	kdev_t devices[MAX_MD_BOOT_DEVS][MAX_REAL];
-} md_setup_args md__initdata = {
-	0,{0},{{0}}
-};
-
-/*
- * Parse the command-line parameters given our kernel, but do not
- * actually try to invoke the MD device now; that is handled by
- * md_setup_drive after the low-level disk drivers have initialised.
- *
- * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which
- *             assigns the task of parsing integer arguments to the
- *             invoked program now).  Added ability to initialise all
- *             the MD devices (by specifying multiple "md=" lines)
- *             instead of just one.  -- KTK
- */
-static int __init md_setup(char *str)
-{
-	int minor, level, factor, fault, i;
-	kdev_t device;
-	char *devnames, *pername;
-
-	if(get_option(&str, &minor) != 2 ||	/* MD Number */
-	   get_option(&str, &level) != 2 ||	/* RAID Personality */
-	   get_option(&str, &factor) != 2 ||	/* Chunk Size */
-	   get_option(&str, &fault) != 2) {
-		printk("md: Too few arguments supplied to md=.\n");
-		return 0;
-	} else if (minor >= MAX_MD_BOOT_DEVS) {
- 		printk ("md: Minor device number too high.\n");
-		return 0;
-	} else if (md_setup_args.set & (1 << minor)) {
-		printk ("md: Warning - md=%d,... has been specified twice;\n"
-			"    will discard the first definition.\n", minor);
- 	}
-	switch(level) {
-#ifdef CONFIG_MD_LINEAR
-	case -1:
-		level = LINEAR<<16;
-		pername = "linear";
- 		break;
-#endif
-#ifdef CONFIG_MD_STRIPED
-	case 0:
-		level = STRIPED<<16;
-		pername = "striped";
- 		break;
-#endif
-	default:
-		printk ("md: The kernel has not been configured for raid%d"
-			" support!\n", level);
-		return 0;
- 	}
-	devnames = str;
-	for (i = 0; str; i++) {
-		if ((device = name_to_kdev_t(str))) {
-			md_setup_args.devices[minor][i] = device;
-		} else {
-			printk ("md: Unknown device name, %s.\n", str);
-			return 0;
-		}
-		if ((str = strchr(str, ',')) != NULL)
-			str++;
-	}
-	if (!i) {
-		printk ("md: No devices specified for md%d?\n", minor);
-		return 0;
-	}
-
-	printk ("md: Will configure md%d (%s) from %s, below.\n",
-		minor, pername, devnames);
-	md_setup_args.devices[minor][i] = (kdev_t) 0;
-	md_setup_args.pers[minor] = level | factor | (fault << 8);
-	md_setup_args.set |= (1 << minor);
-	return 1;
-}
-#endif
-
 static void md_geninit (void)
 {
 	int i;
 
-	for(i = 0; i < MAX_MD_BOOT_DEVS; i++) {
+	for(i = 0; i < MAX_MD_DEVS; i++) {
 		md_blocksizes[i] = 1024;
 		md_size[i] = 0;
 		md_maxreadahead[i] = MD_READAHEAD;
@@ -3525,27 +3255,6 @@
 	md_geninit();
 	return (0);
 }
-
-#ifdef CONFIG_MD_BOOT
-void __init md_setup_drive(void)
-{
-	int minor, i;
-	kdev_t dev;
-	mddev_t*mddev;
-
-	for (minor = 0; minor < MAX_MD_BOOT_DEVS; minor++) {
-		if ((md_setup_args.set & (1 << minor)) == 0)
-			continue;
-		printk("md: Loading md%d.\n", minor);
-		mddev = alloc_mddev(MKDEV(MD_MAJOR,minor));
-		for (i = 0; (dev = md_setup_args.devices[minor][i]); i++)
-			do_md_add (mddev, dev);
-		do_md_start (mddev, md_setup_args.pers[minor]);
-	}
-}
-
-__setup("md=", md_setup);
-#endif
 
 MD_EXPORT_SYMBOL(md_size);
 MD_EXPORT_SYMBOL(register_md_personality);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.3.99-pre5/linux/drivers/block/xd.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/block/xd.c	Thu Apr 13 10:48:16 2000
@@ -1190,7 +1190,7 @@
 {
 	int i, integers[1 + 3*XD_MAXDRIVES];
 
-	get_options (str, ARRAY_SIZE (ints), ints);
+	get_options (str, ARRAY_SIZE (integers), integers);
 	if (integers[0]%3 != 0) {
 		printk("xd: incorrect number of parameters for xd_geo\n");
 		return 1;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/xd.h linux/drivers/block/xd.h
--- v2.3.99-pre5/linux/drivers/block/xd.h	Fri Jan 21 18:19:16 2000
+++ linux/drivers/block/xd.h	Thu Apr 13 10:48:16 2000
@@ -103,9 +103,9 @@
 	const char *name;
 } XD_SIGNATURE;
 
-void xd_setup (char *command,int *integers);
+int xd_setup (char *);
 #ifndef MODULE
-void xd_manual_geo_init (char *command,int *integers);
+int xd_manual_geo_init (char *command);
 #endif /* MODULE */
 static u_char xd_detect (u_char *controller, unsigned int *address);
 static u_char xd_initdrives (void (*init_drive)(u_char drive));
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.99-pre5/linux/drivers/cdrom/cdrom.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/cdrom/cdrom.c	Sat Apr 15 21:20:41 2000
@@ -465,10 +465,8 @@
 	if ((cdi = cdrom_find_device(dev)) == NULL)
 		return -ENODEV;
 
-	/* just CD-RW for now. DVD-RW will come soon, CD-R and DVD-R
-	 * need to be handled differently. */
-	if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_CD_RW))
-			return -EROFS;
+	if (fp->f_mode & FMODE_WRITE)
+		return -EROFS;
 
 	/* if this was a O_NONBLOCK open and we should honor the flags,
 	 * do a quick open without drive/disc integrity checks. */
@@ -964,7 +962,7 @@
 		}
 	}
 	cgc->cmd[9] = cgc->buflen;
-	cgc->data_direction = CGC_DATA_WRITE;
+	cgc->data_direction = CGC_DATA_READ;
 }
 
 static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type)
@@ -986,7 +984,7 @@
 		}
 	}
 	cgc->cmd[9] = cgc->buflen;
-	cgc->data_direction = CGC_DATA_READ;
+	cgc->data_direction = CGC_DATA_WRITE;
 }
 
 static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
@@ -1648,7 +1646,7 @@
 		if (tracks.data > 0) return CDS_DATA_1;
 		/* Policy mode off */
 
-		cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognise!\n");
+		cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
 		return CDS_NO_INFO;
 		}
 
@@ -2529,33 +2527,31 @@
 
 	initialized = 1;
 }
-#endif /* endif CONFIG_SYSCTL */
-
 
-#ifdef MODULE
 static void cdrom_sysctl_unregister(void)
 {
-#ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(cdrom_sysctl_header);
-#endif
 }
 
-int init_module(void)
+#endif /* CONFIG_SYSCTL */
+
+static int __init cdrom_init(void)
 {
 #ifdef CONFIG_SYSCTL
 	cdrom_sysctl_register();
 #endif
-	devfs_handle = devfs_mk_dir (NULL, "cdroms", 6, NULL);
+	devfs_handle = devfs_mk_dir(NULL, "cdroms", 6, NULL);
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cdrom_exit(void)
 {
 	printk(KERN_INFO "Uniform CD-ROM driver unloaded\n");
 #ifdef CONFIG_SYSCTL
 	cdrom_sysctl_unregister();
-#endif /* CONFIG_SYSCTL */
-	devfs_unregister (devfs_handle);
+#endif
+	devfs_unregister(devfs_handle);
 }
-#endif /* endif MODULE */
 
+module_init(cdrom_init);
+module_exit(cdrom_exit);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- v2.3.99-pre5/linux/drivers/cdrom/cm206.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/cdrom/cm206.c	Mon Apr 24 13:39:34 2000
@@ -1483,6 +1483,6 @@
 #endif /* !MODULE */
 /*
  * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o cm206.o cm206.c"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o cm206.o cm206.c"
  * End:
  */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.99-pre5/linux/drivers/char/Config.in	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/Config.in	Wed Apr 12 09:16:31 2000
@@ -210,13 +210,13 @@
 	 dep_tristate '  QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
       fi
    fi
-   dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
+   dep_tristate '  CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
    if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
      if [ "CONFIG_PARPORT_1284" != "n" ]; then
-       dep_tristate 'CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
+       dep_tristate '    CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
      fi
      if [ "$CONFIG_USB" != "n" ]; then
-       dep_tristate 'CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB
+       dep_tristate '    CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB
      fi
    fi
    dep_tristate '  SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/README.computone linux/drivers/char/README.computone
--- v2.3.99-pre5/linux/drivers/char/README.computone	Sun Nov  7 16:37:34 1999
+++ linux/drivers/char/README.computone	Mon Apr 24 13:39:34 2000
@@ -5,24 +5,30 @@
 Release Notes For Linux Kernel 2.2
 These notes have been tested on Linux kernels 2.0 and 2.2.
 
+Please refer to Documentation/computone.txt for information on the driver
+that is included with the kernel sources.
 
-Version: 1.2.4
-Date: 08/04/99
+
+Version: 1.2.9
+Date: 04/12/2000
 Fixes and Updates: Doug McNash 
 Historical Author: Andrew Manison 
+Kernel Integration: Mike Warfield <mhw@wittsend.com>
 
 1. INTRODUCTION
 
 This driver supports the entire family of Intelliport II/Plus controllers
-with the exception of the MicroChannel controllers.
+with the exception of the MicroChannel controllers. 
 
 This driver was developed on the v2.0.x Linux source tree and has been 
-tested up to v2.2.10; it will probably not work with earlier v1.X kernels, 
+tested up to v2.2.14; it will probably not work with earlier v1.X kernels, 
 and has not yet been tested on the v2.1.x tree. The most likely problems 
 will be in patching the kernel sources to support the driver. For this
 reason there are 2 different patch files for 2.0.XX and 2.2.XX kernels.
 Make sure you use the right one!
-Someday soon it should be included in the 2.3.XX tree.
+Note that a version (1.2.5) is included in the 2.2.12+ kernels so this
+will not be a new install but and upgrade.
+
 
 2. QUICK INSTALLATION
 
@@ -31,10 +37,11 @@
 		   `cat /proc/ioports`.  Set the card dip switches to that free 
 		   address.  You may need to configure your BIOS to reserve the
 		   irq for the ISA card.  PCI and EISA parameters are set
-		   automagically and need no attention.  Insert card into 
-		   computer with the power off before or after driver installation.
+		   automagically and need only be set to nonzero values.
+		   Insert card into computer with the power off before or after
+		   driver installation.
 
-Software -
+Software - New Installation
 
 Module installation:
 
@@ -74,6 +81,11 @@
 j) reboot using this kernel
 k) make and run ip2/mkip2dev
 
+Software - Upgrades
+
+a) Install new sources in proper location, usually /usr/src/linux/drivers/char
+b) Follow steps above to create new kernel or modules
+
 3. INSTALLATION
 
 Previously, the driver sources were packaged with a set of patch files
@@ -82,7 +94,8 @@
 the patches if needed, and build any utilities needed.
 What you recieve may be a single patch file in conventional kernel
 patch format build script. That form can also be applied by
-running patch -p1 < ThePatchFile.  Otherwise run ip2build.
+running patch -p1 < ThePatchFile.  Otherwise the drivers source may be
+a tar file, then untar and run ip2build if a new installation.
  
 The driver can be installed as a module (recommended) or built into the 
 kernel. This is selected as for other drivers through the `make config`
@@ -97,20 +110,28 @@
 where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
 12,15) and addr1-4 are the base addresses for up to four controllers. If 
 the irqs are not specified the driver uses the default in ip2/ip2.h (which 
-selects polled mode). If no base addresses are specified the defaults in 
-ip2.h are used. If you are autoloading the driver module with kerneld or
-kmod the base addresses and interrupt number must also be set in ip2/ip2.h
-and recompile or just insert and options line in /etc/modules.conf or both. 
-The options line is equivalent to the command line and takes precidence over 
-what is in ip2.h. 
+selects polled mode). The io addresses are set to io=1 for PCI cards,i
+io=2 for EISA cards or io=[some valid ISA address] for ISA cards.  If no
+base addresses are specified the defaults in ip2.h are used. If you are
+autoloading the driver module with kerneld or kmod the base addresses and
+interrupt number must also be set in ip2/ip2.h and recompile or just insert
+an options line in /etc/modules.conf or both.  The command line takes
+precidence over the options line which takes precidence over the defaults
+in ip2.h. 
+
+command line sample:
+	
+	modprobe ip2 io=1,0x328 irq=1,10
 
 /etc/modules.conf sample:
+
 	options ip2 io=1,0x328 irq=1,10
 	alias char-major-71 ip2
 	alias char-major-72 ip2
 	alias char-major-73 ip2
 
-equivelant ip2.h:
+the equivelant ip2.h:
+
 static ip2config_t ip2config =
 {
 	{1,10,0,0},
@@ -122,15 +143,17 @@
 	}
 };
 
-Specifying an invalid or in-use irq will default the driver into
+Specifying an invalid or in-use ISA irq will default the driver into
 running in polled mode for that card.  If all irq entries are 0 then
-all cards will operate in polled mode.
+all cards will operate in polled mode.  Note that the PCI will be
+assigned it's irq by the BIOS and may not match what you specify.
+It must be non-zero otherwise it will be polled.
 
 Tarball Install:
 
 The whole tarfile should be untarred in the /usr/src/linux/drivers/char/
 directory. Most files required for the driver are placed in the ip2
-subdirectory. Then execute the script 
+subdirectory. Then execute the script (for a new install only)
 
 	ip2build
 
@@ -149,7 +172,7 @@
 If you select the driver as part of the kernel run :
 
 	make depend
-	make zlilo (or whatever you do to create a bootable kernel)
+	make bzImage(,zlilo or whatever you do to create a bootable kernel)
 
 If you selected a module run :
 
@@ -161,7 +184,8 @@
 ports are created. With multiple boards and expansion boxes this will 
 leave gaps in the sequence of device names. ip2mkdev uses Linux tty naming 
 conventions: ttyF0 - ttyF255 for normal devices, and cuf0 - cuf255 for 
-callout devices.
+callout devices.  Note that the callout devices are going away in the
+future and that is what the warning messages are trying to tell you.
 
 4. USING THE DRIVERS
 
@@ -181,7 +205,7 @@
 corresponds to the maximum bit rates those chips are capable.  
 For example if the baud base is 921600 and the baud divisor is 18 then
 the custom rate is 921600/18 = 51200 bps.  See the setserial man page for
-complete details. Of course if stty accepts the higher rates now you can
+complete details. Of course, if stty accepts the higher rates now you can
 use that as well as the standard ioctls().
 
 5. NOTES
@@ -190,6 +214,14 @@
 in all configurations of Linux. If there is any anomalous behaviour that 
 does not match the standard serial port's behaviour please let us know.
 
-Author:  dmcnash@computine.com
+Some installations report that characters fail to echo immediatly at a
+terminal if the kernel/modules are compiled with the CONFIG_M386 and
+the card is run in polling mode on a pentium class machine.  Compiling
+with a more appropriate processor flag or running on interrupt would be
+the fix as well as the wise thing to do.
+
+
+
+Author:  dougm@computone.com
 Testing: larryg@computone.com
-Spport: support@computone.com
+Support: support@computone.com
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c
--- v2.3.99-pre5/linux/drivers/char/agp/agpgart_be.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/agp/agpgart_be.c	Fri Apr 21 16:08:45 2000
@@ -81,7 +81,7 @@
 #endif
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static atomic_t cpus_waiting;
 
 static void ipi_handler(void *null)
@@ -102,9 +102,9 @@
 		barrier();
 }
 #define global_cache_flush smp_flush_cache
-#else				/* __SMP__ */
+#else				/* CONFIG_SMP */
 #define global_cache_flush flush_cache
-#endif				/* __SMP__ */
+#endif				/* CONFIG_SMP */
 
 int agp_backend_acquire(void)
 {
@@ -1764,6 +1764,30 @@
 #endif /* CONFIG_AGP_INTEL */
 
 #ifdef CONFIG_AGP_SIS
+	{ PCI_DEVICE_ID_SI_630,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"630",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_540,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"540",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_620,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"620",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_530,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"530",
+		sis_generic_setup },
 	{ PCI_DEVICE_ID_SI_630,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c
--- v2.3.99-pre5/linux/drivers/char/amiserial.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/char/amiserial.c	Fri Apr 21 15:17:57 2000
@@ -2066,7 +2066,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.99-pre5/linux/drivers/char/bttv.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/bttv.c	Fri Apr 21 15:19:24 2000
@@ -725,6 +725,7 @@
 	{ 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
 	{ 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master" },
 	{ 0x6606217d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x1200bd11, BTTV_PINNACLERAVE,  "Pinnacle PCTV Rave" },
 	{ 0, -1, NULL }
 };
 
@@ -887,6 +888,10 @@
 	{ "TView99 CPH063",
 	  3, 1, 0, 2, 0x551e00, { 2, 0, 1, 1},
 	  { 0x551400, 0x551200, 0, 0, 0x551200 }, 0,1,1,1,1,0 },
+	{ "Pinnacle PCTV Rave",
+	  3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0,
+	  1,1,1,1,0 },
+	
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.3.99-pre5/linux/drivers/char/bttv.h	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/bttv.h	Fri Apr 21 15:19:24 2000
@@ -271,6 +271,7 @@
 #define BTTV_TYPHOON_TVIEW 0x24
 #define BTTV_PXELVWPLTVPRO 0x25
 #define BTTV_MAGICTVIEW063 0x26
+#define BTTV_PINNACLERAVE  0x27
 
 
 #define AUDIO_TUNER        0x00
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v2.3.99-pre5/linux/drivers/char/busmouse.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/char/busmouse.c	Tue Apr 25 17:38:33 2000
@@ -1,22 +1,11 @@
 /*
- * linux/drivers/char/mouse.c
+ * linux/drivers/char/busmouse.c
  *
- * Copyright (C) 1995 - 1998 Russell King
- *  Protocol taken from busmouse.c
+ * Copyright (C) 1995 - 1998 Russell King <linux@arm.linux.org.uk>
+ *  Protocol taken from original busmouse.c
  *  read() waiting taken from psaux.c
  *
  * Medium-level interface for quadrature or bus mice.
- *
- * Currently, the majority of kernel busmice drivers in the
- * kernel common code to talk to userspace.  This driver
- * attempts to rectify this situation by presenting a
- * simple and safe interface to the mice and user.
- *
- * This driver:
- *  - is SMP safe
- *  - handles multiple opens
- *  - handles the wakeups and locking
- *  - has optional blocking reads
  */
 
 #include <linux/module.h>
@@ -40,10 +29,8 @@
 /* Uncomment this if your mouse drivers expect the kernel to
  * return with EAGAIN if the mouse does not have any events
  * available, even if the mouse is opened in nonblocking mode.
- *
- * Should this be on a per-mouse basis?  If so, add an entry to
- * the struct busmouse structure and add the relevent flag to
- * the drivers.
+ * Please report use of this "feature" to the author using the
+ * above address.
  */
 /*#define BROKEN_MOUSE*/
 
@@ -56,7 +43,6 @@
 	struct fasync_struct	*fasyncptr;
 	char			active;
 	char			buttons;
-	char			latch_buttons;
 	char			ready;
 	int			dxpos;
 	int			dypos;
@@ -75,32 +61,19 @@
 static struct busmouse_data *busmouse_data[NR_MICE];
 static DECLARE_MUTEX(mouse_sem);
 
-/* a mouse driver just has to interface with these functions
- *  These are !!!OLD!!!  Do not use!!!
- */
-void add_mouse_movement(int dx, int dy)
-{
-	struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
-
-	mse->dxpos += dx;
-	mse->dypos += dy;
-	mse->ready = 1;
-	wake_up(&mse->wait);
-}
-
-int add_mouse_buttonchange(int set, int value)
-{
-	struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
-
-	mse->buttons = (mse->buttons & ~set) ^ value;
-	mse->ready = 1;
-	wake_up(&mse->wait);
-	return mse->buttons;
-}
-
-/* New interface.  !!! Use this one !!!
- * These routines will most probably be called from interrupt.
+/**
+ *	busmouse_add_movement - notification of a change of mouse position
+ *	@mousedev: mouse number
+ *	@dx: delta X movement
+ *	@dy: delta Y movement
+ *	@buttons: new button state
+ *
+ *	Updates the mouse position and button information. The mousedev
+ *	parameter is the value returned from register_busmouse. The
+ *	movement information is updated, and the new button state is
+ *	saved.  A waiting user thread is woken.
  */
+ 
 void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
 {
 	struct busmouse_data *mse = busmouse_data[mousedev];
@@ -113,7 +86,6 @@
 		add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
 
 		mse->buttons = buttons;
-//		mse->latch_buttons |= buttons;
 		mse->dxpos += dx;
 		mse->dypos += dy;
 		mse->ready = 1;
@@ -143,6 +115,17 @@
 	}
 }
 
+/**
+ *	busmouse_add_movement - notification of a change of mouse position
+ *	@mousedev: mouse number
+ *	@dx: delta X movement
+ *	@dy: delta Y movement
+ *
+ *	Updates the mouse position. The mousedev parameter is the value
+ *	returned from register_busmouse. The movement information is
+ *	updated, and a waiting user thread is woken.
+ */
+ 
 void busmouse_add_movement(int mousedev, int dx, int dy)
 {
 	struct busmouse_data *mse = busmouse_data[mousedev];
@@ -150,6 +133,18 @@
 	busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
 }
 
+/**
+ *	busmouse_add_buttons - notification of a change of button state
+ *	@mousedev: mouse number
+ *	@clear: mask of buttons to clear
+ *	@eor: mask of buttons to change
+ *
+ *	Updates the button state. The mousedev parameter is the value
+ *	returned from register_busmouse. The buttons are updated by:
+ *		new_state = (old_state & ~clear) ^ eor
+ *	A waiting user thread is woken up.
+ */
+ 
 void busmouse_add_buttons(int mousedev, int clear, int eor)
 {
 	struct busmouse_data *mse = busmouse_data[mousedev];
@@ -191,7 +186,6 @@
 static int busmouse_open(struct inode *inode, struct file *file)
 {
 	struct busmouse_data *mse;
-	unsigned long flags;
 	unsigned int mousedev;
 	int ret = -ENODEV;
 
@@ -219,7 +213,7 @@
 
 	MOD_INC_USE_COUNT;
 
-	spin_lock_irqsave(&mse->lock, flags);
+	spin_lock_irq(&mse->lock);
 
 	mse->ready   = 0;
 	mse->dxpos   = 0;
@@ -229,7 +223,7 @@
 	else
 		mse->buttons = 7;
 
-	spin_unlock_irqrestore(&mse->lock, flags);
+	spin_unlock_irq(&mse->lock);
 end:
 	up(&mouse_sem);
 	return ret;
@@ -244,21 +238,20 @@
 {
 	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
 	int dxpos, dypos, buttons;
 
 	if (count < 3)
 		return -EINVAL;
 
-	spin_lock_irqsave(&mse->lock, flags);
+	spin_lock_irq(&mse->lock);
 
 	if (!mse->ready) {
 #ifdef BROKEN_MOUSE
-		spin_unlock_irqrestore(&mse->lock, flags);
+		spin_unlock_irq(&mse->lock);
 		return -EAGAIN;
 #else
 		if (file->f_flags & O_NONBLOCK) {
-			spin_unlock_irqrestore(&mse->lock, flags);
+			spin_unlock_irq(&mse->lock);
 			return -EAGAIN;
 		}
 
@@ -266,9 +259,9 @@
 repeat:
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (!mse->ready && !signal_pending(current)) {
-			spin_unlock_irqrestore(&mse->lock, flags);
+			spin_unlock_irq(&mse->lock);
 			schedule();
-			spin_lock_irqsave(&mse->lock, flags);
+			spin_lock_irq(&mse->lock);
 			goto repeat;
 		}
 
@@ -276,7 +269,7 @@
 		remove_wait_queue(&mse->wait, &wait);
 
 		if (signal_pending(current)) {
-			spin_unlock_irqrestore(&mse->lock, flags);
+			spin_unlock_irq(&mse->lock);
 			return -ERESTARTSYS;
 		}
 #endif
@@ -285,7 +278,6 @@
 	dxpos = mse->dxpos;
 	dypos = mse->dypos;
 	buttons = mse->buttons;
-//	mse->latch_buttons = mse->buttons;
 
 	if (dxpos < -127)
 		dxpos =- 127;
@@ -306,7 +298,7 @@
 	 */
 	mse->ready = mse->dxpos || mse->dypos;
 
-	spin_unlock_irqrestore(&mse->lock, flags);
+	spin_unlock_irq(&mse->lock);
 
 	/* Write out data to the user.  Format is:
 	 *   byte 0 - identifer (0x80) and (inverted) mouse buttons
@@ -326,6 +318,7 @@
 	return count;
 }
 
+/* No kernel lock held - fine */
 static unsigned int busmouse_poll(struct file *file, poll_table *wait)
 {
 	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
@@ -412,6 +405,7 @@
 int unregister_busmouse(int mousedev)
 {
 	int err = -EINVAL;
+
 	if (mousedev < 0)
 		return 0;
 	if (mousedev >= NR_MICE) {
@@ -434,7 +428,7 @@
 		goto fail;
 	}
 
-	err=misc_deregister(&busmouse_data[mousedev]->miscdev);
+	err = misc_deregister(&busmouse_data[mousedev]->miscdev);
 
 	kfree(busmouse_data[mousedev]);
 	busmouse_data[mousedev] = NULL;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/busmouse.h linux/drivers/char/busmouse.h
--- v2.3.99-pre5/linux/drivers/char/busmouse.h	Mon Mar 27 08:08:23 2000
+++ linux/drivers/char/busmouse.h	Tue Apr 25 17:38:33 2000
@@ -1,12 +1,12 @@
 /*
- * linux/drivers/char/mouse.h
+ * linux/drivers/char/busmouse.h
  *
  * Copyright (C) 1995 - 1998 Russell King
  *
  * Prototypes for generic busmouse interface
  */
-#ifndef MOUSE_H
-#define MOUSE_H
+#ifndef BUSMOUSE_H
+#define BUSMOUSE_H
 
 struct busmouse {
 	int minor;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/cpia.c linux/drivers/char/cpia.c
--- v2.3.99-pre5/linux/drivers/char/cpia.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/cpia.c	Tue Apr 25 16:53:13 2000
@@ -1577,9 +1577,13 @@
 	cmd[7] = 0;
 
 	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
-	if (retval)
+	if (retval) {
 		DBG("%x - failed, retval=%d\n", command, retval);
-	else {
+		if (command == CPIA_COMMAND_GetColourParams ||
+		    command == CPIA_COMMAND_GetColourBalance ||
+		    command == CPIA_COMMAND_GetExposure)
+			up(&cam->param_lock);
+	} else {
 		switch(command) {
 		case CPIA_COMMAND_GetCPIAVersion:
 			cam->params.version.firmwareVersion = data[0];
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/efirtc.c linux/drivers/char/efirtc.c
--- v2.3.99-pre5/linux/drivers/char/efirtc.c	Sat Feb 26 22:31:44 2000
+++ linux/drivers/char/efirtc.c	Fri Apr 21 15:21:24 2000
@@ -39,7 +39,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#define EFI_RTC_VERSION		"0.1"
+#define EFI_RTC_VERSION		"0.2"
 
 #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
 /*
@@ -47,7 +47,7 @@
  */
 #define EFI_RTC_EPOCH		1998
 
-static spinlock_t efi_rtc_lock;
+static spinlock_t efi_rtc_lock = SPIN_LOCK_UNLOCKED;
 
 static int efi_rtc_ioctl(struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg);
@@ -153,6 +153,8 @@
 	efi_time_t	eft;
 	efi_time_cap_t	cap;
 	struct rtc_time	wtime;
+	struct rtc_wkalrm *ewp;
+	unsigned char	enabled, pending;
 
 	switch (cmd) {
 		case RTC_UIE_ON:
@@ -203,6 +205,50 @@
 			spin_unlock_irqrestore(&efi_rtc_lock,flags);
 
 			return status == EFI_SUCCESS ? 0 : -EINVAL;
+
+		case RTC_WKALM_SET:
+
+			if (!capable(CAP_SYS_TIME)) return -EACCES;
+
+			ewp = (struct rtc_wkalrm *)arg;
+
+			if (  get_user(enabled, &ewp->enabled)
+			   || copy_from_user(&wtime, &ewp->time, sizeof(struct rtc_time)) )
+				return -EFAULT;
+
+			convert_to_efi_time(&wtime, &eft);
+			
+			spin_lock_irqsave(&efi_rtc_lock, flags);
+			/*
+			 * XXX Fixme:
+			 * As of EFI 0.92 with the firmware I have on my
+			 * machine this call does not seem to work quite 
+			 * right
+			 */
+			status = efi.set_wakeup_time((efi_bool_t)enabled, &eft);
+
+			spin_unlock_irqrestore(&efi_rtc_lock,flags);
+
+			return status == EFI_SUCCESS ? 0 : -EINVAL;
+
+		case RTC_WKALM_RD:
+
+			spin_lock_irqsave(&efi_rtc_lock, flags);
+
+			status = efi.get_wakeup_time((efi_bool_t *)&enabled, (efi_bool_t *)&pending, &eft);
+
+			spin_unlock_irqrestore(&efi_rtc_lock,flags);
+
+			if (status != EFI_SUCCESS) return -EINVAL;
+
+			ewp = (struct rtc_wkalrm *)arg;
+
+			if (  put_user(enabled, &ewp->enabled)
+			   || put_user(pending, &ewp->pending)) return -EFAULT;
+
+			convert_from_efi_time(&eft, &wtime);
+
+			return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time));
 	}
 	return -EINVAL;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/fip_firm.h linux/drivers/char/ip2/fip_firm.h
--- v2.3.99-pre5/linux/drivers/char/ip2/fip_firm.h	Thu Aug 26 13:05:35 1999
+++ linux/drivers/char/ip2/fip_firm.h	Mon Apr 24 13:39:35 2000
@@ -2,10 +2,10 @@
 /* -31232 bytes read from ff.lod */
 
 unsigned char fip_firm[] __initdata = {
-0x3C,0x42,0x8A,0xE1,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x57,0x65,0x64,0x20,0x4A,0x75,0x6E,0x20,0x32,0x33,0x20,0x31,0x35,0x3A,0x33,0x30,
-0x3A,0x31,0x33,0x20,0x31,0x39,0x39,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0xE9,0x68,0x0F,0x42,0x65,0x47,0x69,0x4E,0x6E,0x49,0x6E,0x47,0x20,0x6F,0x46,0x20,
+0x3C,0x42,0x37,0x18,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x57,0x65,0x64,0x20,0x44,0x65,0x63,0x20,0x30,0x31,0x20,0x31,0x32,0x3A,0x32,0x34,
+0x3A,0x33,0x30,0x20,0x31,0x39,0x39,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xE9,0x6C,0x0F,0x42,0x65,0x47,0x69,0x4E,0x6E,0x49,0x6E,0x47,0x20,0x6F,0x46,0x20,
 0x63,0x4F,0x64,0x45,0xCC,0x13,0x5A,0x15,0xE8,0x16,0x76,0x18,0x04,0x1A,0x92,0x1B,
 0x20,0x1D,0xAE,0x1E,0x3C,0x20,0xCA,0x21,0x58,0x23,0xE6,0x24,0x74,0x26,0x02,0x28,
 0x90,0x29,0x1E,0x2B,0xAC,0x2C,0x3A,0x2E,0xC8,0x2F,0x56,0x31,0xE4,0x32,0x72,0x34,
@@ -18,7 +18,7 @@
 0x53,0x33,0xDB,0x25,0x07,0x00,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x83,0xE3,0x0C,0xEB,
 0x20,0x90,0x3C,0x01,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x80,0xE3,0xC0,0xEB,0x12,0x90,
 0x8A,0x1E,0x0D,0x01,0x3C,0x02,0x75,0x06,0x80,0xE3,0x0C,0xEB,0x04,0x90,0x80,0xE3,
-0xC0,0x53,0x50,0x8B,0x1E,0xBA,0x13,0x8E,0xDB,0xE8,0x4C,0x65,0x55,0x8B,0xEC,0x53,
+0xC0,0x53,0x50,0x8B,0x1E,0xBA,0x13,0x8E,0xDB,0xE8,0x6A,0x65,0x55,0x8B,0xEC,0x53,
 0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06,0xD1,0xE3,
 0x2E,0x8B,0x9F,0x44,0x00,0x8D,0x47,0x2A,0x1E,0x5A,0x1F,0x5B,0x5D,0xC3,0x55,0x8B,
 0xEC,0x53,0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06,
@@ -32,33 +32,33 @@
 0x26,0x8A,0x47,0x24,0x88,0x44,0x15,0x26,0x8A,0x47,0x5A,0x88,0x44,0x0E,0x33,0xC0,
 0x89,0x44,0x06,0x89,0x44,0x08,0x88,0x44,0x0B,0x88,0x44,0x0A,0xB0,0x21,0xB4,0x64,
 0x89,0x44,0x04,0x89,0x44,0x02,0xB0,0x55,0x88,0x44,0x0D,0x88,0x44,0x0C,0xE8,0x6A,
-0x00,0x72,0x5B,0xE8,0xC9,0x00,0xE8,0xBD,0x10,0x89,0x44,0x08,0x80,0x7C,0x0F,0x01,
-0x74,0x29,0xE8,0x2B,0x02,0xE8,0x7F,0x02,0x80,0x7C,0x0F,0x03,0x74,0x1D,0xE8,0xA5,
+0x00,0x72,0x5B,0xE8,0xC9,0x00,0xE8,0xC1,0x10,0x89,0x44,0x08,0x80,0x7C,0x0F,0x01,
+0x74,0x29,0xE8,0x2B,0x02,0xE8,0x7F,0x02,0x80,0x7C,0x0F,0x03,0x74,0x1D,0xE8,0xA9,
 0x10,0x8B,0xF8,0x2B,0x44,0x08,0x3D,0xA0,0x0F,0x72,0x10,0x89,0x7C,0x08,0x33,0xC0,
 0x87,0x44,0x06,0x85,0xC0,0x75,0x04,0xC6,0x44,0x0A,0xFF,0x8A,0x44,0x0A,0x84,0xC0,
-0x75,0x0B,0xB8,0x08,0x00,0xE8,0x4C,0x4A,0xE8,0xA9,0x01,0x73,0xBF,0xE8,0x4F,0x01,
-0x81,0x66,0x48,0x7F,0xFF,0x83,0x66,0x7A,0xBF,0xB0,0x02,0xE8,0x00,0x0E,0x8A,0x44,
+0x75,0x0B,0xB8,0x08,0x00,0xE8,0x6A,0x4A,0xE8,0xA9,0x01,0x73,0xBF,0xE8,0x4F,0x01,
+0x81,0x66,0x48,0x7F,0xFF,0x83,0x66,0x7A,0xBF,0xB0,0x02,0xE8,0x04,0x0E,0x8A,0x44,
 0x0A,0x98,0x07,0x1F,0x5F,0x5E,0x5A,0x59,0x5B,0x5D,0xC3,0x81,0x4E,0x48,0x80,0x00,
-0xB0,0x40,0xE8,0x1F,0x4A,0xE8,0x6B,0x40,0x73,0x2A,0xE8,0x49,0x10,0x8B,0xD8,0xB0,
-0x05,0xE8,0x10,0x4A,0xF6,0x46,0x27,0x02,0x75,0x1A,0xE8,0x39,0x10,0x2B,0xC3,0x3D,
-0x58,0x1B,0x72,0xEB,0x81,0x66,0x48,0x7F,0xFF,0xB0,0x02,0xE8,0xC0,0x0D,0xC6,0x44,
-0x0A,0x01,0xF9,0xC3,0x83,0x4E,0x7A,0x40,0xF8,0xC3,0xFB,0xB0,0x01,0xE8,0xE4,0x49,
-0xFA,0xE8,0x95,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xB0,0x4E,0xE6,0x0A,0xFB,0xB0,
-0x01,0xE8,0xD0,0x49,0xFA,0xE8,0x81,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xC3,0xFA,
-0xE8,0x76,0x1E,0xE4,0xEC,0x88,0x44,0x16,0xE4,0xE4,0x88,0x44,0x17,0xE4,0xF8,0x88,
+0xB0,0x40,0xE8,0x3D,0x4A,0xE8,0x89,0x40,0x73,0x2A,0xE8,0x4D,0x10,0x8B,0xD8,0xB0,
+0x05,0xE8,0x2E,0x4A,0xF6,0x46,0x27,0x02,0x75,0x1A,0xE8,0x3D,0x10,0x2B,0xC3,0x3D,
+0x58,0x1B,0x72,0xEB,0x81,0x66,0x48,0x7F,0xFF,0xB0,0x02,0xE8,0xC4,0x0D,0xC6,0x44,
+0x0A,0x01,0xF9,0xC3,0x83,0x4E,0x7A,0x40,0xF8,0xC3,0xFB,0xB0,0x01,0xE8,0x02,0x4A,
+0xFA,0xE8,0x99,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xB0,0x4E,0xE6,0x0A,0xFB,0xB0,
+0x01,0xE8,0xEE,0x49,0xFA,0xE8,0x85,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xC3,0xFA,
+0xE8,0x7A,0x1E,0xE4,0xEC,0x88,0x44,0x16,0xE4,0xE4,0x88,0x44,0x17,0xE4,0xF8,0x88,
 0x44,0x18,0xE4,0xF0,0x88,0x44,0x19,0xE4,0x10,0x88,0x44,0x1A,0xE4,0x12,0x88,0x44,
 0x1B,0xE4,0x14,0x88,0x44,0x1C,0xE4,0x34,0x88,0x44,0x1D,0xE4,0x36,0x88,0x44,0x1E,
 0xE4,0xD8,0x24,0x01,0x8A,0xE0,0xE4,0xDA,0x24,0x02,0x0A,0xC4,0x88,0x44,0x1F,0x8A,
-0x44,0x10,0xE8,0xC9,0x1F,0x8A,0x44,0x11,0xE8,0x31,0x21,0x8A,0x44,0x12,0xE8,0x85,
-0x21,0x8A,0x44,0x13,0xE8,0x3F,0x21,0xC6,0x86,0xA1,0x00,0x00,0xE4,0x14,0x24,0x10,
+0x44,0x10,0xE8,0xCD,0x1F,0x8A,0x44,0x11,0xE8,0x35,0x21,0x8A,0x44,0x12,0xE8,0x89,
+0x21,0x8A,0x44,0x13,0xE8,0x43,0x21,0xC6,0x86,0xA1,0x00,0x00,0xE4,0x14,0x24,0x10,
 0xE6,0x14,0xE4,0x12,0x24,0x3D,0xE6,0x12,0x8A,0x44,0x15,0x3C,0x01,0x72,0x1E,0x77,
 0x16,0xB0,0x11,0xE6,0x34,0xB0,0x13,0xE6,0x36,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,
 0x12,0x0C,0x40,0xE6,0x12,0xEB,0x06,0xE4,0x12,0x0C,0x02,0xE6,0x12,0x8A,0x44,0x0F,
 0x3C,0x01,0x74,0x06,0x3C,0x02,0x74,0x0A,0xEB,0x0E,0xE4,0x12,0x0C,0x08,0xE6,0x12,
 0xEB,0x06,0xE4,0x12,0x0C,0x10,0xE6,0x12,0xE8,0x2F,0xFF,0x8A,0x44,0x14,0x3C,0x02,
 0x75,0x08,0xB0,0x55,0x88,0x44,0x0C,0x88,0x44,0x0D,0xB0,0x21,0xB4,0x64,0x89,0x44,
-0x04,0x89,0x44,0x02,0xE4,0x0C,0x0C,0x10,0xE6,0x0C,0xE8,0xCF,0x39,0xFB,0xC3,0xE8,
-0x41,0x3F,0x73,0x08,0xFB,0xB0,0x0A,0xE8,0xEA,0x48,0xEB,0xF3,0xFA,0xE8,0x99,0x1D,
+0x04,0x89,0x44,0x02,0xE4,0x0C,0x0C,0x10,0xE6,0x0C,0xE8,0xED,0x39,0xFB,0xC3,0xE8,
+0x5F,0x3F,0x73,0x08,0xFB,0xB0,0x0A,0xE8,0x08,0x49,0xEB,0xF3,0xFA,0xE8,0x9D,0x1D,
 0x8A,0x64,0x16,0x8A,0x44,0x17,0x89,0x86,0x94,0x00,0xE6,0xE4,0x8A,0xC4,0xE6,0xEC,
 0x8A,0x64,0x18,0x8A,0x44,0x19,0x89,0x86,0x96,0x00,0xE6,0xF0,0x8A,0xC4,0xE6,0xF8,
 0x8A,0x44,0x1A,0xE6,0x10,0x8A,0x44,0x1B,0xE6,0x12,0x8A,0x44,0x1C,0xE6,0x14,0x8A,
@@ -73,947 +73,949 @@
 0xFF,0xAA,0xE8,0xA7,0xFF,0xAA,0xE8,0xA3,0xFF,0xAA,0xE8,0x9F,0xFF,0x88,0x44,0x0C,
 0x89,0x5C,0x02,0x80,0x44,0x0B,0x04,0x89,0x7E,0x22,0x83,0x6E,0x24,0x04,0x83,0x46,
 0x1A,0x04,0x80,0x7E,0x26,0x02,0x74,0x06,0x80,0x66,0x26,0xFD,0xFB,0xC3,0x60,0xB0,
-0xFD,0xE8,0xE4,0x3E,0x61,0xFB,0xC3,0xFA,0x80,0x7C,0x0F,0x03,0x75,0x09,0xC6,0x44,
-0x0B,0x00,0xE8,0xC7,0x38,0xFB,0xC3,0xC4,0x7E,0x14,0x8B,0x4E,0x3A,0x85,0xC9,0x75,
+0xFD,0xE8,0x02,0x3F,0x61,0xFB,0xC3,0xFA,0x80,0x7C,0x0F,0x03,0x75,0x09,0xC6,0x44,
+0x0B,0x00,0xE8,0xE5,0x38,0xFB,0xC3,0xC4,0x7E,0x14,0x8B,0x4E,0x3A,0x85,0xC9,0x75,
 0x35,0x26,0x8B,0x0D,0x47,0x47,0xE3,0xEA,0x3B,0x7E,0x04,0x76,0x22,0xB8,0x02,0x00,
 0x39,0x46,0x2E,0x77,0x07,0xC7,0x46,0x2E,0x00,0x00,0xEB,0x13,0x8B,0x5E,0x2C,0x89,
 0x5E,0x04,0x26,0xC7,0x07,0x00,0x00,0x43,0x43,0x89,0x5E,0x2C,0x29,0x46,0x2E,0x85,
 0xC9,0x78,0xCE,0x89,0x4E,0x3A,0x8A,0x44,0x0D,0x8B,0x5C,0x04,0x26,0x8A,0x25,0x47,
 0x3A,0xC4,0x75,0x16,0xFE,0x4C,0x0B,0xFF,0x44,0x06,0xE8,0x0F,0xFF,0xE2,0xED,0x88,
-0x44,0x0D,0x89,0x5C,0x04,0x89,0x4E,0x3A,0xEB,0xA7,0xC6,0x44,0x0A,0xFE,0xE8,0x5B,
-0x38,0xFB,0xC3,0x90,0xE8,0xAF,0x0D,0x8A,0xE8,0x8A,0x0E,0xCB,0x13,0xB3,0x07,0x8A,
+0x44,0x0D,0x89,0x5C,0x04,0x89,0x4E,0x3A,0xEB,0xA7,0xC6,0x44,0x0A,0xFE,0xE8,0x79,
+0x38,0xFB,0xC3,0x90,0xE8,0xB3,0x0D,0x8A,0xE8,0x8A,0x0E,0xCB,0x13,0xB3,0x07,0x8A,
 0xC1,0xEE,0xEB,0x00,0xEC,0x3A,0xC1,0x75,0x09,0x02,0xCD,0xFE,0xCB,0x75,0xF0,0xEB,
 0x0C,0x90,0x88,0x0E,0xCB,0x13,0x8A,0xE8,0xBB,0xFF,0xFF,0xF9,0xC3,0x88,0x0E,0xCB,
 0x13,0xF8,0xC3,0x90,0xBB,0x3F,0x3F,0x8A,0x8E,0x9E,0x00,0xBA,0xFE,0x00,0xEC,0x8A,
 0xE8,0x32,0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0xE8,0xE5,0xFF,0x73,
 0x01,0xC3,0xBA,0xD0,0x00,0xBB,0x03,0x03,0x8A,0x8E,0x9F,0x00,0xEC,0x8A,0xE8,0x32,
 0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,
-0x80,0x3E,0xC8,0x13,0x00,0x75,0x07,0xB0,0x0A,0xE8,0x08,0x47,0xEB,0xF2,0xFB,0x33,
+0x80,0x3E,0xC8,0x13,0x00,0x75,0x07,0xB0,0x0A,0xE8,0x26,0x47,0xEB,0xF2,0xFB,0x33,
 0xDB,0x8A,0x1E,0xC9,0x13,0x43,0x43,0x83,0xFB,0x7E,0x76,0x07,0x33,0xDB,0xB0,0x02,
-0xE8,0xF1,0x46,0x2E,0x8B,0xAF,0x44,0x00,0x83,0x7E,0x08,0x00,0x74,0xE7,0x88,0x1E,
-0xC9,0x13,0xB0,0x02,0xE8,0xDD,0x46,0xFA,0xF7,0x46,0x38,0x40,0x00,0x74,0x14,0xE8,
-0x92,0x1B,0xE8,0x7F,0xFF,0x72,0x1C,0x33,0xD2,0x8A,0x96,0x9F,0x00,0x83,0xC2,0x0E,
-0xEB,0x0C,0x90,0xE8,0x73,0x1B,0xE8,0x83,0xFF,0x72,0x08,0xBA,0x48,0x00,0xE8,0x33,
+0xE8,0x0F,0x47,0x2E,0x8B,0xAF,0x44,0x00,0x83,0x7E,0x08,0x00,0x74,0xE7,0x88,0x1E,
+0xC9,0x13,0xB0,0x02,0xE8,0xFB,0x46,0xFA,0xF7,0x46,0x38,0x40,0x00,0x74,0x14,0xE8,
+0x96,0x1B,0xE8,0x7F,0xFF,0x72,0x1C,0x33,0xD2,0x8A,0x96,0x9F,0x00,0x83,0xC2,0x0E,
+0xEB,0x0C,0x90,0xE8,0x77,0x1B,0xE8,0x83,0xFF,0x72,0x08,0xBA,0x48,0x00,0xE8,0x33,
 0xFF,0x73,0xAB,0x23,0xCB,0x89,0x8E,0x9A,0x00,0x89,0x96,0x9C,0x00,0xFE,0x86,0xB5,
-0x00,0xC6,0x06,0xC8,0x13,0x00,0xB0,0x0A,0xE8,0x63,0x0A,0xFB,0xEB,0x89,0x10,0x18,
+0x00,0xC6,0x06,0xC8,0x13,0x00,0xB0,0x0A,0xE8,0x67,0x0A,0xFB,0xEB,0x89,0x10,0x18,
 0x08,0x28,0x33,0xC0,0xA0,0x05,0x01,0x8A,0xC8,0x24,0x40,0x75,0x24,0xC7,0x06,0x7C,
-0x12,0x70,0x45,0xC7,0x06,0x42,0x12,0x01,0x00,0xC6,0x06,0x54,0x12,0x02,0xB0,0x08,
+0x12,0x8E,0x45,0xC7,0x06,0x42,0x12,0x01,0x00,0xC6,0x06,0x54,0x12,0x02,0xB0,0x08,
 0xF6,0xC1,0x01,0x74,0x02,0xB0,0x04,0xA3,0x46,0x12,0xA2,0x4C,0x12,0xA2,0x94,0x12,
-0xC3,0xC7,0x06,0x7C,0x12,0x98,0x45,0xA0,0x0F,0x01,0x84,0xC0,0x75,0x0E,0x6A,0x00,
-0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xAD,0x0C,0x90,0xC7,0x06,0x44,0x12,
+0xC3,0xC7,0x06,0x7C,0x12,0xB6,0x45,0xA0,0x0F,0x01,0x84,0xC0,0x75,0x0E,0x6A,0x00,
+0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xB1,0x0C,0x90,0xC7,0x06,0x44,0x12,
 0x01,0x00,0xA3,0x42,0x12,0x8B,0xD8,0xC1,0xE3,0x04,0x88,0x1E,0x94,0x12,0xBE,0xE2,
 0x05,0x2B,0xF0,0x8B,0xC8,0x33,0xDB,0x8B,0xFB,0x2E,0xAC,0x88,0x85,0x48,0x12,0x8A,
 0xD8,0x0C,0x05,0xE6,0xFE,0x8A,0xE0,0xEB,0x00,0xE4,0xFE,0x32,0xC4,0xA8,0x3F,0x74,
-0x03,0xE9,0x9A,0x00,0xE4,0x00,0x88,0x85,0x50,0x12,0x8A,0xE0,0x24,0x30,0xBA,0x10,
+0x03,0xE9,0x9E,0x00,0xE4,0x00,0x88,0x85,0x50,0x12,0x8A,0xE0,0x24,0x30,0xBA,0x10,
 0xFF,0x3C,0x30,0x74,0x12,0x80,0xFC,0x04,0x74,0x0A,0xBA,0x04,0x03,0xF6,0x06,0x08,
 0x01,0xFE,0x74,0x03,0xBA,0x08,0x0F,0x88,0x95,0x4C,0x12,0x02,0xFA,0x32,0xC0,0xF6,
-0xC4,0x08,0x74,0x02,0xB0,0x01,0x88,0x85,0x58,0x12,0x8A,0xC4,0x3C,0x35,0x74,0x57,
-0x3C,0x34,0x74,0x53,0x3C,0x04,0x74,0x4F,0x3C,0x14,0x74,0x4B,0x3C,0x15,0x74,0x47,
-0xA8,0x40,0x74,0x25,0xC6,0x85,0x54,0x12,0x04,0xD1,0xE7,0xB4,0x03,0x8A,0xC3,0x89,
-0x85,0x5C,0x12,0x8A,0xC3,0x8A,0xE3,0x80,0xCC,0x01,0x89,0x85,0x64,0x12,0xD1,0xEF,
-0x47,0xE2,0x03,0xEB,0x1A,0x90,0xE9,0x70,0xFF,0xC6,0x85,0x54,0x12,0x02,0xD1,0xE7,
-0x8A,0xE6,0x8A,0xC3,0x0C,0x04,0x89,0x85,0x5C,0x12,0xD1,0xEF,0x47,0xE2,0xE7,0x33,
-0xC0,0x8A,0xC7,0xA3,0x46,0x12,0xC3,0xC6,0x85,0x54,0x12,0x06,0xEB,0xBB,0xC6,0x85,
-0x54,0x12,0x00,0x33,0xC0,0x88,0x85,0x50,0x12,0x88,0x85,0x4C,0x12,0x88,0x85,0x58,
-0x12,0xEB,0xA6,0xC7,0x46,0x26,0x02,0x12,0x8B,0x46,0x1E,0x89,0x46,0x00,0x89,0x46,
-0x22,0x8B,0x46,0x20,0x89,0x46,0x24,0xC7,0x46,0x1A,0x00,0x00,0xC3,0xC7,0x46,0x3C,
-0x80,0x00,0xC7,0x46,0x38,0x01,0x00,0x1E,0x56,0x8B,0x76,0x30,0x89,0x76,0x04,0x89,
-0x76,0x14,0x8E,0x5E,0x06,0x33,0xC0,0x89,0x04,0x46,0x46,0x89,0x76,0x2C,0x89,0x46,
-0x3A,0x8B,0x46,0x32,0x48,0x48,0x89,0x46,0x2E,0x5E,0x1F,0xC3,0x33,0xC0,0x89,0x46,
-0x48,0x89,0x46,0x4A,0xC7,0x46,0x46,0xAE,0x01,0x89,0x46,0x4E,0x8B,0x46,0x44,0x89,
-0x46,0x50,0x8B,0x46,0x42,0x89,0x46,0x40,0x89,0x46,0x08,0xC3,0x33,0xC0,0x89,0x46,
-0x76,0x89,0x46,0x78,0xC7,0x46,0x7A,0x10,0x00,0x56,0x1E,0x8B,0x76,0x70,0x89,0x76,
-0x10,0x89,0x76,0x0C,0x8E,0x5E,0x12,0xC7,0x04,0x00,0x00,0x8B,0x46,0x72,0x89,0x46,
-0x74,0x1F,0x5E,0xC3,0x89,0x56,0x18,0x89,0x56,0x02,0x89,0x56,0x06,0x89,0x56,0x0A,
-0x89,0x56,0x0E,0x89,0x56,0x12,0x89,0x56,0x16,0x8B,0xD8,0x4B,0x4B,0xC1,0xE3,0x02,
-0xBF,0x02,0x00,0x89,0x7E,0x1E,0x03,0xFB,0x89,0x7E,0x30,0x03,0xFB,0x89,0x7E,0x42,
-0x03,0xFB,0x89,0x7E,0x70,0x83,0xEB,0x08,0x89,0x5E,0x20,0x89,0x5E,0x32,0x89,0x5E,
-0x44,0x89,0x5E,0x72,0x50,0xE8,0x2B,0xFF,0xE8,0x71,0xFF,0xE8,0x3F,0xFF,0xE8,0x8B,
-0xFF,0x58,0xC3,0xB8,0x10,0x75,0xC1,0xE8,0x04,0x0E,0x5B,0x03,0xC3,0xA3,0xBA,0x13,
-0x83,0x3E,0x42,0x12,0x00,0x74,0x07,0x80,0x3E,0x94,0x12,0x00,0x75,0x0E,0x6A,0x00,
-0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xBD,0x0A,0x90,0xB8,0x30,0x7A,0xC1,
-0xE8,0x04,0x40,0xA3,0xC0,0x13,0x2B,0x06,0x12,0x01,0xF7,0xD8,0x33,0xD2,0x8B,0xCA,
-0x8A,0x0E,0x94,0x12,0xF7,0xF1,0x3D,0x80,0x00,0x77,0x0E,0x6A,0x00,0x1F,0xC6,0x06,
-0x93,0x12,0x25,0x9C,0x0E,0xE8,0x90,0x0A,0x90,0x48,0x3D,0xFF,0x07,0x72,0x03,0xB8,
-0xFF,0x07,0xA3,0xC2,0x13,0x33,0xC9,0x8A,0x0E,0x94,0x12,0x33,0xF6,0xB8,0x00,0x09,
-0x2E,0x8B,0xAC,0x44,0x00,0x89,0x46,0x4C,0x40,0x46,0x46,0xE2,0xF3,0x8A,0x0E,0x94,
-0x12,0x33,0xF6,0x8B,0x16,0xC0,0x13,0xA1,0xC2,0x13,0x2E,0x8B,0xAC,0x44,0x00,0xE8,
-0x22,0xFF,0x03,0xD0,0x46,0x46,0xE2,0xF2,0xC3,0x33,0xC0,0x2E,0x8B,0xAD,0x44,0x00,
-0x89,0x46,0x08,0x47,0x47,0xE2,0xF4,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD,
-0x44,0x00,0x89,0x86,0x9E,0x00,0x81,0x4E,0x38,0x00,0x20,0x47,0x47,0xFE,0xC4,0x80,
-0xFC,0x04,0x72,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE3,0x59,0x83,0xE9,0x10,0x74,0x05,
-0xF7,0xD9,0xE8,0xC4,0xFF,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD,0x44,0x00,
-0x89,0x86,0x9E,0x00,0x83,0x4E,0x38,0x40,0x47,0x47,0x80,0xC4,0x10,0x79,0x04,0x32,
-0xE4,0xFE,0xC0,0xE2,0xE6,0x59,0x83,0xE9,0x10,0x74,0x05,0xF7,0xD9,0xE8,0x99,0xFF,
-0xC3,0xE8,0xD2,0xFF,0xC3,0x89,0x08,0x98,0x08,0xC6,0x08,0xF1,0x08,0x8B,0x0E,0x42,
-0x12,0x33,0xF6,0x51,0x56,0x33,0xDB,0x8B,0xCB,0x8A,0x94,0x48,0x12,0x8A,0x8C,0x4C,
-0x12,0x8A,0x9C,0x54,0x12,0x8B,0xFE,0xC1,0xE7,0x05,0x85,0xDB,0x75,0x02,0xB1,0x10,
-0x2E,0xFF,0x97,0xF5,0x08,0x5E,0x59,0x46,0xE2,0xD9,0xC3,0x01,0xCC,0x03,0xD0,0x00,
-0xE8,0x02,0xD0,0x00,0xE8,0x01,0xD0,0x00,0xE8,0x00,0xD0,0x00,0xE8,0x04,0xD0,0xA8,
-0xDA,0x00,0xDC,0x00,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0xA8,
-0xDA,0x20,0xDC,0x00,0xDE,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00,0xD8,0x03,0xCC,0x03,
+0xC4,0x08,0x74,0x02,0xB0,0x01,0x88,0x85,0x58,0x12,0x8A,0xC4,0x3C,0x35,0x74,0x5B,
+0x3C,0x36,0x74,0x57,0x3C,0x34,0x74,0x53,0x3C,0x04,0x74,0x4F,0x3C,0x14,0x74,0x4B,
+0x3C,0x15,0x74,0x47,0xA8,0x40,0x74,0x25,0xC6,0x85,0x54,0x12,0x04,0xD1,0xE7,0xB4,
+0x03,0x8A,0xC3,0x89,0x85,0x5C,0x12,0x8A,0xC3,0x8A,0xE3,0x80,0xCC,0x01,0x89,0x85,
+0x64,0x12,0xD1,0xEF,0x47,0xE2,0x03,0xEB,0x1A,0x90,0xE9,0x6C,0xFF,0xC6,0x85,0x54,
+0x12,0x02,0xD1,0xE7,0x8A,0xE6,0x8A,0xC3,0x0C,0x04,0x89,0x85,0x5C,0x12,0xD1,0xEF,
+0x47,0xE2,0xE7,0x33,0xC0,0x8A,0xC7,0xA3,0x46,0x12,0xC3,0xC6,0x85,0x54,0x12,0x06,
+0xEB,0xBB,0xC6,0x85,0x54,0x12,0x00,0x33,0xC0,0x88,0x85,0x50,0x12,0x88,0x85,0x4C,
+0x12,0x88,0x85,0x58,0x12,0xEB,0xA6,0xC7,0x46,0x26,0x02,0x12,0x8B,0x46,0x1E,0x89,
+0x46,0x00,0x89,0x46,0x22,0x8B,0x46,0x20,0x89,0x46,0x24,0xC7,0x46,0x1A,0x00,0x00,
+0xC3,0xC7,0x46,0x3C,0x80,0x00,0xC7,0x46,0x38,0x01,0x00,0x1E,0x56,0x8B,0x76,0x30,
+0x89,0x76,0x04,0x89,0x76,0x14,0x8E,0x5E,0x06,0x33,0xC0,0x89,0x04,0x46,0x46,0x89,
+0x76,0x2C,0x89,0x46,0x3A,0x8B,0x46,0x32,0x48,0x48,0x89,0x46,0x2E,0x5E,0x1F,0xC3,
+0x33,0xC0,0x89,0x46,0x48,0x89,0x46,0x4A,0xC7,0x46,0x46,0xAE,0x01,0x89,0x46,0x4E,
+0x8B,0x46,0x44,0x89,0x46,0x50,0x8B,0x46,0x42,0x89,0x46,0x40,0x89,0x46,0x08,0xC3,
+0x33,0xC0,0x89,0x46,0x76,0x89,0x46,0x78,0xC7,0x46,0x7A,0x10,0x00,0x56,0x1E,0x8B,
+0x76,0x70,0x89,0x76,0x10,0x89,0x76,0x0C,0x8E,0x5E,0x12,0xC7,0x04,0x00,0x00,0x8B,
+0x46,0x72,0x89,0x46,0x74,0x1F,0x5E,0xC3,0x89,0x56,0x18,0x89,0x56,0x02,0x89,0x56,
+0x06,0x89,0x56,0x0A,0x89,0x56,0x0E,0x89,0x56,0x12,0x89,0x56,0x16,0x8B,0xD8,0x4B,
+0x4B,0xC1,0xE3,0x02,0xBF,0x02,0x00,0x89,0x7E,0x1E,0x03,0xFB,0x89,0x7E,0x30,0x03,
+0xFB,0x89,0x7E,0x42,0x03,0xFB,0x89,0x7E,0x70,0x83,0xEB,0x08,0x89,0x5E,0x20,0x89,
+0x5E,0x32,0x89,0x5E,0x44,0x89,0x5E,0x72,0x50,0xE8,0x2B,0xFF,0xE8,0x71,0xFF,0xE8,
+0x3F,0xFF,0xE8,0x8B,0xFF,0x58,0xC3,0xB8,0x30,0x75,0xC1,0xE8,0x04,0x0E,0x5B,0x03,
+0xC3,0xA3,0xBA,0x13,0x83,0x3E,0x42,0x12,0x00,0x74,0x07,0x80,0x3E,0x94,0x12,0x00,
+0x75,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xBD,0x0A,0x90,
+0xB8,0x30,0x7A,0xC1,0xE8,0x04,0x40,0xA3,0xC0,0x13,0x2B,0x06,0x12,0x01,0xF7,0xD8,
+0x33,0xD2,0x8B,0xCA,0x8A,0x0E,0x94,0x12,0xF7,0xF1,0x3D,0x80,0x00,0x77,0x0E,0x6A,
+0x00,0x1F,0xC6,0x06,0x93,0x12,0x25,0x9C,0x0E,0xE8,0x90,0x0A,0x90,0x48,0x3D,0xFF,
+0x07,0x72,0x03,0xB8,0xFF,0x07,0xA3,0xC2,0x13,0x33,0xC9,0x8A,0x0E,0x94,0x12,0x33,
+0xF6,0xB8,0x00,0x09,0x2E,0x8B,0xAC,0x44,0x00,0x89,0x46,0x4C,0x40,0x46,0x46,0xE2,
+0xF3,0x8A,0x0E,0x94,0x12,0x33,0xF6,0x8B,0x16,0xC0,0x13,0xA1,0xC2,0x13,0x2E,0x8B,
+0xAC,0x44,0x00,0xE8,0x22,0xFF,0x03,0xD0,0x46,0x46,0xE2,0xF2,0xC3,0x33,0xC0,0x2E,
+0x8B,0xAD,0x44,0x00,0x89,0x46,0x08,0x47,0x47,0xE2,0xF4,0xC3,0x51,0x33,0xC0,0x0A,
+0xC2,0x2E,0x8B,0xAD,0x44,0x00,0x89,0x86,0x9E,0x00,0x81,0x4E,0x38,0x00,0x20,0x47,
+0x47,0xFE,0xC4,0x80,0xFC,0x04,0x72,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE3,0x59,0x83,
+0xE9,0x10,0x74,0x05,0xF7,0xD9,0xE8,0xC4,0xFF,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,
+0x8B,0xAD,0x44,0x00,0x89,0x86,0x9E,0x00,0x83,0x4E,0x38,0x40,0x47,0x47,0x80,0xC4,
+0x10,0x79,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE6,0x59,0x83,0xE9,0x10,0x74,0x05,0xF7,
+0xD9,0xE8,0x99,0xFF,0xC3,0xE8,0xD2,0xFF,0xC3,0x8D,0x08,0x9C,0x08,0xCA,0x08,0xF5,
+0x08,0x8B,0x0E,0x42,0x12,0x33,0xF6,0x51,0x56,0x33,0xDB,0x8B,0xCB,0x8A,0x94,0x48,
+0x12,0x8A,0x8C,0x4C,0x12,0x8A,0x9C,0x54,0x12,0x8B,0xFE,0xC1,0xE7,0x05,0x85,0xDB,
+0x75,0x02,0xB1,0x10,0x2E,0xFF,0x97,0xF9,0x08,0x5E,0x59,0x46,0xE2,0xD9,0xC3,0x01,
+0xCC,0x03,0xD0,0x00,0xE8,0x02,0xD0,0x00,0xE8,0x01,0xD0,0x00,0xE8,0x00,0xD0,0x00,
+0xE8,0x04,0xD0,0xA8,0xDA,0x00,0xDC,0x00,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,
+0xCC,0x04,0xD0,0xA8,0xDA,0x20,0xDC,0x00,0xDE,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00,
+0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,
 0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,
-0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0x00,
-0xDA,0x20,0xDC,0x03,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00,
-0xD8,0x00,0xCC,0x00,0xD0,0x00,0x00,0x56,0x52,0x1E,0x0E,0x1F,0xBE,0x2B,0x09,0x33,
-0xD2,0xFC,0xAD,0x85,0xC0,0x74,0x0D,0x8A,0xD4,0xEE,0xAD,0x85,0xC0,0x74,0x05,0x8A,
-0xD4,0xEE,0xEB,0xEE,0x1F,0x5A,0x5E,0xC3,0xE4,0x80,0x84,0xC0,0x74,0x16,0x78,0x14,
-0xB0,0x27,0xE6,0xFC,0xB0,0x11,0xE6,0x34,0xE4,0xFC,0x3C,0x27,0x75,0x06,0xE4,0x11,
-0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xB0,
-0x10,0xEE,0x88,0x86,0xAF,0x00,0xB0,0x11,0x83,0xC2,0x04,0xEE,0x83,0xC2,0x02,0xEE,
-0xB0,0x13,0x83,0xC2,0x02,0xEE,0x83,0xC2,0x02,0xEE,0x2E,0xA1,0x2E,0x2D,0x89,0x86,
-0x94,0x00,0x83,0xEA,0x0E,0xEE,0x83,0xC2,0x02,0x8A,0xC4,0xEE,0x83,0xC2,0x04,0xB0,
-0x03,0xEE,0x88,0x86,0xA8,0x00,0x83,0xEA,0x04,0x32,0xC0,0xEE,0x83,0xC2,0x02,0xB0,
-0x89,0xEE,0x88,0x86,0xA6,0x00,0x0C,0x06,0xEE,0xB0,0x40,0xB4,0x38,0x89,0x46,0x1C,
-0xC7,0x46,0x36,0x38,0x00,0x83,0xC2,0x04,0x32,0xC0,0xEE,0x88,0x86,0xA7,0x00,0xC3,
-0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xEC,0x3A,0x86,0xAF,0x00,0x75,0x24,
-0x83,0xC2,0x04,0xEC,0x3C,0x11,0x75,0x1C,0x83,0xC2,0x06,0xEC,0x3C,0x13,0x75,0x14,
-0x83,0xEA,0x08,0x8A,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x02,0xEC,0x24,0xC0,0x3C,0xC0,
-0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x33,0xC9,0x8B,0xD1,0x8B,0xF1,0x8A,0x0E,0x94,0x12,
-0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x0E,0x8A,
-0x86,0x9E,0x00,0xE6,0xFE,0x32,0xC0,0xE6,0x80,0x42,0xE8,0xFA,0xFE,0x83,0xC6,0x08,
-0xE2,0xE1,0x85,0xD2,0x74,0x03,0xE8,0x05,0x08,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,
-0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x73,
-0x16,0xE8,0x12,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,
-0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x16,
-0xE8,0x46,0x16,0xE8,0xD2,0xFE,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C,
-0x9C,0x0E,0xE8,0xE3,0x07,0x90,0x83,0xC6,0x08,0xE2,0xD9,0xC3,0x33,0xC9,0x8B,0xF1,
-0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x16,
-0xE8,0x21,0x16,0xE8,0x2A,0xFF,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C,
-0x9C,0x0E,0xE8,0xB3,0x07,0x90,0x46,0x46,0xE2,0xDA,0xC3,0x0C,0x00,0x00,0x10,0x00,
-0x13,0x12,0x00,0x00,0x14,0x00,0x28,0x3C,0x00,0x1B,0x3E,0x00,0x00,0x2A,0x00,0x00,
-0x2C,0x00,0x00,0x42,0x00,0x14,0xD8,0x00,0x00,0xDA,0x00,0x00,0x34,0x00,0x11,0x36,
-0x00,0x13,0x38,0x00,0x11,0x3A,0x00,0x13,0x00,0x00,0x56,0x50,0x52,0xBE,0x2B,0x0B,
-0x2E,0xAD,0x85,0xC0,0x74,0x06,0x92,0x2E,0xAC,0xEE,0xEB,0xF4,0x5A,0x58,0x5E,0xC3,
-0x53,0x2E,0xA1,0x5C,0x22,0xE6,0xE4,0xE6,0xF0,0x8A,0xC4,0xE6,0xEC,0xE6,0xF8,0xE8,
-0xD8,0xFF,0xB0,0x4B,0xE6,0x10,0xB0,0x50,0xE6,0x12,0xB0,0x38,0xE6,0x14,0xE8,0xAE,
-0x15,0xB0,0x46,0xE6,0x0A,0xE8,0xA7,0x15,0xB0,0x1A,0xE6,0x0A,0xE8,0xA0,0x15,0xB0,
-0x22,0xE6,0x0A,0xE8,0x99,0x15,0xE8,0xFD,0x06,0x8B,0xD8,0xE4,0x16,0xA8,0x04,0x75,
-0x18,0xE8,0xF2,0x06,0x2B,0xC3,0x3D,0x32,0x00,0x72,0xF0,0x6A,0x00,0x1F,0xC6,0x06,
-0x93,0x12,0x23,0x9C,0x0E,0xE8,0x10,0x07,0x90,0xE8,0xDA,0x06,0x2B,0xC3,0x3D,0x24,
-0x00,0x77,0x1B,0xB0,0x31,0xE6,0xFC,0x56,0x51,0x55,0xB9,0x10,0x00,0x2E,0x8B,0xAC,
-0x44,0x00,0x81,0x4E,0x38,0x80,0x00,0x46,0x46,0xE2,0xF2,0x5D,0x59,0x5E,0xE8,0x69,
-0xFF,0xE8,0x4B,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0x44,0x15,0x5B,0xC3,0x33,0xF6,0x8B,
-0x0E,0x42,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,
-0x17,0x15,0xE8,0x5B,0xFF,0x83,0xC6,0x20,0xE2,0xE9,0xC3,0x8B,0xC2,0x05,0x04,0x00,
-0x89,0x46,0x28,0x2E,0xA1,0x2E,0x2D,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x89,
-0x86,0x92,0x00,0xC6,0x86,0xA3,0x00,0x0A,0xC6,0x86,0xC3,0x00,0x03,0x52,0x83,0xC2,
-0x04,0x8A,0x86,0xA6,0x00,0x0C,0x06,0xEE,0x5A,0x83,0xC2,0x02,0xB0,0x05,0xEE,0x88,
-0x86,0xA5,0x00,0xC3,0xE8,0x03,0xFF,0xE8,0xE5,0x14,0xB0,0x42,0xE6,0x0A,0xF7,0x46,
-0x38,0x80,0x00,0x74,0x06,0x2E,0xA1,0x98,0x22,0xEB,0x04,0x2E,0xA1,0x68,0x22,0xC7,
-0x46,0x1C,0x0C,0x00,0x89,0x86,0x94,0x00,0x89,0x86,0x96,0x00,0x89,0x86,0x8E,0x00,
-0x89,0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xE6,0xF0,0xE6,0xE4,0x8A,0xC4,0xE6,0xF8,
-0xE6,0xEC,0xC6,0x86,0xC3,0x00,0x03,0xE8,0xA5,0x14,0xB0,0x1A,0xE6,0x0A,0xB0,0x10,
-0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,
-0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x76,0x14,0xE8,0x5A,
-0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,
-0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,0x4C,0x14,0xE8,0x74,0xFF,
-0x46,0x46,0xE2,0xEA,0xC3,0x90,0x83,0x3E,0x44,0x12,0x00,0x75,0x14,0xB0,0x01,0xBA,
-0x06,0x01,0xEE,0x2A,0xC0,0xEE,0xB0,0x02,0xEE,0xB0,0x04,0xEE,0xB8,0x00,0x02,0xEB,
-0x0F,0xBA,0x06,0x01,0xB0,0x40,0xEE,0xB8,0x01,0x00,0x8A,0x0E,0x0E,0x01,0xD3,0xE0,
-0xA3,0x88,0x12,0xC3,0xA1,0x88,0x12,0xA3,0x84,0x12,0x2D,0x20,0x00,0xA3,0x8A,0x12,
-0x2D,0x20,0x00,0xA3,0x82,0x12,0xC7,0x06,0x86,0x12,0x20,0x00,0xC7,0x06,0x80,0x12,
-0x32,0x00,0xC3,0x83,0x3E,0x44,0x12,0x00,0x74,0x76,0x8B,0x0E,0x42,0x12,0x33,0xF6,
-0x8A,0xA4,0x54,0x12,0x84,0xE4,0x74,0x5F,0x8A,0x84,0x48,0x12,0x0C,0x04,0xE6,0xFE,
-0xF6,0xC4,0x04,0x74,0x25,0xB0,0x1B,0xBA,0x00,0x00,0xEE,0xEB,0x00,0x2A,0xC0,0xBA,
-0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0x32,0xC0,0xBA,0x02,0x00,0xEE,
-0xEB,0x00,0xBA,0x00,0x00,0xB0,0x00,0xEE,0xEB,0x2D,0xB0,0x1F,0xBA,0x00,0x00,0xEE,
-0xEB,0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0xD1,
-0xE6,0x8A,0x84,0x5D,0x12,0xD1,0xEE,0xF6,0xD0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xBA,
-0x00,0x00,0xB0,0x0A,0xEE,0xEB,0x00,0xE4,0x04,0xEB,0x00,0xE4,0x04,0x46,0xE2,0x90,
-0xC3,0x90,0xB8,0x14,0x00,0xBA,0x3E,0xFF,0xEF,0xB8,0x06,0x00,0xBA,0x32,0xFF,0xEF,
-0xB8,0x0F,0x00,0xBA,0x34,0xFF,0xEF,0xBA,0x36,0xFF,0xEF,0x83,0x3E,0x44,0x12,0x00,
-0x75,0x16,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,0x12,0x00,0xBA,0x3A,0xFF,0xEF,
-0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,
-0x12,0x00,0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0xFC,
-0x00,0xBA,0x28,0xFF,0xEF,0xFB,0x83,0x3E,0x44,0x12,0x00,0x74,0x07,0xB8,0xCC,0x00,
-0xBA,0x28,0xFF,0xEF,0xC3,0x00,0xFF,0xFF,0x20,0x24,0x28,0xFF,0x2C,0xFF,0xFF,0x30,
-0x34,0x38,0xFF,0xFF,0x3C,0x90,0x3C,0x0F,0x77,0x0E,0xBB,0x15,0x0E,0x2E,0xD7,0x3C,
-0xFF,0x74,0x05,0x8A,0xD8,0xF8,0xC3,0x90,0x2A,0xDB,0xF9,0xC3,0x83,0x3E,0x44,0x12,
-0x00,0x74,0x27,0xA0,0x06,0x01,0x80,0x26,0x06,0x01,0x30,0x80,0x3E,0x06,0x01,0x30,
-0x75,0x18,0xB9,0x02,0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,
-0xBA,0x04,0x01,0xED,0xAB,0xE2,0xF1,0xEB,0x16,0x90,0xB9,0x04,0x00,0xBF,0xC4,0x13,
-0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xEC,0xAA,0xE2,0xF1,0xFA,
-0x90,0xBE,0xC4,0x13,0xAD,0x80,0xE4,0x3F,0x80,0xFC,0x02,0x74,0x0E,0x6A,0x00,0x1F,
-0xC6,0x06,0x93,0x12,0x0A,0x9C,0x0E,0xE8,0x3E,0x04,0x90,0xAD,0x3C,0x0F,0x75,0xED,
-0x8A,0xC4,0xE8,0x81,0xFF,0x72,0xE6,0x88,0x1E,0x1A,0x01,0xC6,0x06,0x8E,0x12,0x00,
-0xB0,0x00,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xC6,0x06,0x8F,0x12,0x40,0x83,
-0x3E,0x44,0x12,0x00,0x75,0x06,0xB8,0x0C,0x00,0xEB,0x04,0x90,0xB8,0x4C,0x00,0xBA,
-0x28,0xFF,0xEF,0xC3,0x83,0x3E,0x44,0x12,0x00,0x75,0x01,0xC3,0xA1,0x50,0x12,0x0B,
-0x06,0x52,0x12,0x0A,0xC4,0xA8,0x08,0x74,0xF2,0xA0,0x0F,0x01,0x2A,0xE4,0x50,0xFF,
-0x36,0xBA,0x13,0x1F,0xE8,0x36,0x56,0x83,0xC4,0x02,0x6A,0x00,0x1F,0x33,0xC0,0xA3,
-0xBC,0x13,0xA0,0x0F,0x01,0xA3,0xBE,0x13,0x8B,0x1E,0xBC,0x13,0x8A,0x87,0x50,0x12,
-0xF6,0x87,0x50,0x12,0x08,0x74,0x0D,0x24,0x07,0x8A,0xE0,0xBE,0xCC,0x00,0xA0,0xBC,
-0x13,0xE8,0x7A,0x3D,0xFF,0x06,0xBC,0x13,0xFF,0x0E,0xBE,0x13,0x75,0xDA,0xC3,0x90,
-0x1E,0x33,0xC0,0x8E,0xD8,0xB0,0x01,0xE8,0x3A,0x3D,0x1F,0xC3,0x33,0xC9,0x8B,0xF1,
-0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xC7,0x46,0x62,0x1A,0x44,0xC7,0x46,
-0x7C,0xDE,0x3B,0xC7,0x46,0x7E,0xC4,0x3B,0xC7,0x86,0x80,0x00,0xCE,0x3C,0xE8,0xAB,
-0x16,0xC6,0x86,0xC0,0x00,0x11,0x83,0x7E,0x08,0x00,0x74,0x07,0x51,0x56,0xE8,0x19,
-0x33,0x5E,0x59,0x46,0x46,0xE2,0xCD,0xC3,0x33,0xC9,0x8B,0xF1,0x8B,0xF9,0x8A,0x0E,
-0x94,0x12,0xC1,0xE9,0x02,0xE3,0x13,0x2E,0x8B,0xAC,0x44,0x00,0x8A,0x86,0x9E,0x00,
-0x88,0x85,0x6C,0x12,0x83,0xC6,0x08,0x47,0xE2,0xED,0xC3,0xFA,0xFC,0xB0,0xC0,0xBA,
-0x00,0x01,0xEE,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,0xBF,0x16,0x01,0xB9,0xCC,
-0x77,0x2B,0xCF,0xD1,0xE9,0xF3,0xAB,0xBC,0x40,0x12,0xE8,0xD9,0x02,0xE8,0x56,0x3C,
-0xBE,0xC8,0x0F,0xE8,0xD8,0x3C,0xF4,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,
-0xF6,0x06,0x0A,0x01,0x80,0x74,0x0B,0xBE,0x17,0x55,0xE8,0xC1,0x3C,0xB0,0x01,0xE8,
-0x92,0x3C,0xE8,0xB3,0x00,0xE8,0xFA,0xF5,0xE8,0x08,0xF8,0xE8,0x0F,0xF9,0xE8,0x85,
-0xFA,0xE8,0xB6,0xFA,0xE8,0xEF,0xFC,0xE8,0xC2,0x10,0xE8,0xE9,0x3B,0xE8,0xB2,0xFD,
-0xE8,0x30,0xFD,0xE8,0x54,0x02,0xC6,0x06,0x8F,0x12,0xC0,0xE8,0xBB,0xFA,0xE8,0xEB,
-0xFA,0xE8,0xE9,0xFB,0xE8,0xAF,0xFC,0xE8,0x8D,0xFC,0xE8,0x1F,0xFF,0xE8,0x58,0xFF,
-0xE8,0xDB,0xFD,0xE8,0x16,0xFE,0x33,0xC0,0xBE,0x5A,0x05,0xE8,0x70,0x3C,0xE8,0xA3,
-0xFE,0xE8,0xE0,0xFC,0xFB,0xBE,0x86,0x44,0xE8,0x63,0x3C,0xE9,0xB0,0x2D,0x56,0x98,
-0x8B,0xF0,0x8B,0x42,0x52,0x85,0xC0,0x75,0x27,0xC7,0x42,0x52,0x01,0x00,0x53,0x36,
-0x8B,0x9C,0x2C,0x01,0xF6,0xC3,0x01,0x75,0x0C,0x36,0x89,0x68,0x52,0x36,0x89,0xAC,
-0x2C,0x01,0x5B,0x5E,0xC3,0x36,0x89,0xAC,0x2C,0x01,0x36,0x89,0xAC,0x1C,0x01,0x5B,
-0x5E,0xC3,0x56,0x98,0x8B,0xF0,0x33,0xED,0x36,0x8B,0x84,0x1C,0x01,0xA8,0x01,0x75,
-0x15,0x8B,0xE8,0x33,0xC0,0x87,0x42,0x52,0x36,0x89,0x84,0x1C,0x01,0xA8,0x01,0x74,
-0x05,0x36,0x89,0x84,0x2C,0x01,0x5E,0xC3,0x56,0x51,0x33,0xF6,0xB8,0x01,0x00,0xB9,
-0x08,0x00,0x89,0x84,0x1C,0x01,0x89,0x84,0x2C,0x01,0x46,0x46,0xE2,0xF4,0x59,0x5E,
-0xC3,0x90,0xBB,0x01,0x00,0x8B,0xE8,0xFF,0x4E,0x6E,0x74,0x0A,0x8B,0xDD,0x8B,0x46,
-0x58,0xA8,0x01,0x74,0xF0,0xC3,0x8B,0x46,0x48,0xA9,0x08,0x00,0x74,0x45,0xF7,0x46,
-0x38,0x40,0x00,0x74,0x27,0xE8,0x5C,0x10,0x80,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24,
-0xBF,0x88,0x86,0xA8,0x00,0xEE,0x60,0xB0,0xFE,0xE8,0x6C,0x32,0x61,0xB0,0x02,0xE8,
-0x4C,0xFF,0x8B,0x46,0x48,0x24,0xF7,0x89,0x46,0x48,0xEB,0x17,0xE8,0x2A,0x10,0x81,
-0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,
-0x8B,0x46,0x48,0xA9,0x04,0x00,0x74,0x14,0xB0,0x02,0xE8,0x21,0xFF,0x8B,0x46,0x48,
-0x24,0xFB,0x89,0x46,0x48,0x60,0xB0,0xDF,0xE8,0x2D,0x32,0x61,0x33,0xC0,0x87,0x46,
-0x58,0xF6,0xC3,0x01,0x75,0x0B,0x36,0x89,0x47,0x58,0xA8,0x01,0x75,0x0D,0xE9,0x74,
-0xFF,0xA3,0x22,0x01,0xA8,0x01,0x75,0x03,0xE9,0x6A,0xFF,0x89,0x1E,0x32,0x01,0xC3,
-0xBB,0x01,0x00,0x8B,0xE8,0xF7,0x46,0x38,0x40,0x00,0x74,0x15,0xE8,0xD5,0x0F,0x80,
-0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x0A,0x8B,0xDD,0x8B,0x46,0x56,0xA8,0x01,0x74,0xE3,
-0xC3,0x8B,0x46,0x26,0x80,0xE4,0xFE,0x80,0xCC,0x02,0x89,0x46,0x26,0xB0,0x02,0xE8,
-0xBC,0xFE,0x33,0xC0,0x87,0x46,0x56,0xF6,0xC3,0x01,0x75,0x0A,0x36,0x89,0x47,0x56,
-0xA8,0x01,0x75,0x0B,0xEB,0xBD,0xA3,0x20,0x01,0xA8,0x01,0x75,0x02,0xEB,0xB4,0x89,
-0x1E,0x30,0x01,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA0,0x90,0x12,0x84,0xC0,
-0x75,0x49,0xA1,0x22,0x01,0xA8,0x01,0x75,0x03,0xE8,0xF6,0xFE,0xA1,0x20,0x01,0xA8,
-0x01,0x75,0x03,0xE8,0x8A,0xFF,0xA1,0xAC,0x13,0x48,0x78,0x05,0x74,0x45,0xA3,0xAC,
-0x13,0xA1,0xAE,0x13,0x48,0x78,0x05,0x74,0x51,0xA3,0xAE,0x13,0xA1,0xB0,0x13,0x48,
-0x78,0x05,0x74,0x63,0xA3,0xB0,0x13,0xA1,0x7E,0x12,0x40,0x78,0x03,0xA3,0x7E,0x12,
-0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0xA0,0x91,0x12,0x40,0x3C,
-0x02,0x72,0x0B,0x33,0xC0,0xA2,0x91,0x12,0xFF,0x16,0x7C,0x12,0xEB,0xA4,0xA2,0x91,
-0x12,0xEB,0x9F,0xA0,0x8E,0x12,0x32,0x06,0x8F,0x12,0xA2,0x8E,0x12,0x0A,0x06,0x1A,
-0x01,0xBA,0x00,0x01,0xEE,0xB8,0x2C,0x01,0xEB,0xA4,0x83,0x3E,0x84,0x12,0x10,0x72,
-0x11,0xBA,0x28,0xFF,0xED,0x0C,0x81,0xEF,0xE8,0x39,0x37,0xBA,0x28,0xFF,0xED,0x24,
-0x7E,0xEF,0xB8,0x04,0x00,0xEB,0x92,0xC6,0x06,0x8D,0x12,0x01,0xE8,0x25,0x37,0xC6,
-0x06,0x8D,0x12,0x00,0xA1,0xB2,0x13,0xEB,0x8B,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF,
-0x6B,0xC3,0x19,0xBA,0x62,0xFF,0xEF,0xB8,0x0A,0x00,0xBA,0x60,0xFF,0xEF,0xB8,0x01,
-0xE0,0xBA,0x66,0xFF,0xEF,0xB8,0xFF,0xFF,0xBA,0x52,0xFF,0xEF,0xB8,0x09,0xC0,0xBA,
-0x56,0xFF,0xEF,0xC7,0x06,0xAC,0x13,0x2C,0x01,0xC7,0x06,0xAE,0x13,0x04,0x00,0xC6,
-0x06,0x91,0x12,0x00,0xC3,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF,0x6B,0xC3,0x05,0xD1,
-0xE8,0xA3,0x18,0x01,0xC3,0x90,0x52,0xBA,0x50,0xFF,0xED,0x5A,0xC3,0x90,0x53,0x51,
-0x8B,0x1E,0x18,0x01,0xB9,0x32,0x05,0x90,0xE2,0xFE,0x4B,0x75,0xF7,0x59,0x5B,0xC3,
-0xB0,0x80,0xBA,0x00,0x01,0x0A,0x06,0x1A,0x01,0xEE,0xC3,0x90,0xB0,0x40,0xEB,0xF2,
-0xB0,0xC0,0xEB,0xEE,0xB0,0x00,0xEB,0xEA,0xFA,0x60,0x06,0x1E,0x16,0x2B,0xDB,0x8E,
-0xDB,0x2E,0xA1,0x9C,0x4C,0x2E,0xA3,0x74,0x4C,0xA0,0x93,0x12,0x98,0x8B,0xE8,0x89,
-0x26,0x2D,0x7A,0x80,0x3E,0xCA,0x13,0x00,0x74,0x03,0xE9,0x51,0x42,0xE8,0xC0,0xFF,
-0xE8,0xAB,0xFF,0xE8,0xA8,0xFF,0xB0,0x20,0xC6,0x06,0x90,0x12,0x00,0xFF,0x16,0x7C,
-0x12,0x8B,0xFD,0x83,0xFF,0x0A,0x72,0x11,0xE8,0xB9,0xFF,0xE8,0x90,0xFF,0xE8,0xAB,
-0xFF,0xE8,0x8A,0xFF,0x83,0xEF,0x0A,0xEB,0xEA,0x0B,0xFF,0x74,0x0F,0xE8,0xA4,0xFF,
-0xE8,0x7B,0xFF,0xE8,0x9A,0xFF,0xE8,0x75,0xFF,0x4F,0x75,0xF1,0xE8,0x95,0xFF,0xE8,
-0x6C,0xFF,0xEB,0xB9,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88,0x86,0xA5,0x00,0xC3,
-0x8A,0x86,0xA6,0x00,0x0C,0x02,0xEE,0xC3,0x8B,0x76,0x38,0xF7,0xC6,0x01,0x00,0x74,
-0xEF,0x8B,0x4E,0x36,0x8B,0x46,0x2E,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89,
-0x46,0x2E,0x01,0x4E,0x34,0xC4,0x7E,0x04,0x26,0x01,0x0D,0x8B,0x7E,0x2C,0x83,0xEA,
-0x04,0xF3,0x6C,0x8E,0xC1,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72,0x12,0xF7,0xC6,0x20,
-0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8,0xA0,0xFC,0xC3,0xF7,
-0xC6,0x04,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xCE,0x10,0x89,0x76,0x38,0x8A,0x86,0xA7,
-0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xC2,0x08,0xEE,0x83,0xEA,0x08,0x8B,0xC3,
-0x3D,0x40,0x00,0x72,0x01,0xC3,0x81,0x4E,0x38,0x00,0x04,0x83,0xC2,0x02,0x8A,0x86,
-0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0x8A,0x86,0xA6,0x00,0x0C,0x02,
-0xEE,0xC3,0xF7,0x46,0x38,0x01,0x00,0x74,0xF1,0x8B,0x4E,0x2E,0x32,0xDB,0x8A,0xBE,
-0xA3,0x00,0x83,0xC2,0x06,0xC4,0x76,0x04,0x8B,0x7E,0x2C,0x83,0xF9,0x08,0x72,0x2C,
-0xEC,0xA8,0x01,0x74,0x16,0x8A,0xE0,0x83,0xEA,0x0A,0xEC,0x83,0xC2,0x0A,0x84,0xE7,
-0x75,0x51,0xAA,0xFE,0xC3,0x49,0x83,0xF9,0x08,0x73,0xE5,0x32,0xFF,0x26,0x01,0x1C,
-0x01,0x5E,0x34,0x89,0x76,0x04,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x3B,0x4E,0x3C,0x72,
-0x11,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xFD,
-0xFB,0xC3,0xF6,0x46,0x38,0x04,0x74,0x15,0x83,0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00,
-0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x02,0xEE,0x83,0xC2,0x02,0x3D,0x40,0x00,
-0x72,0x5D,0xC3,0x32,0xFF,0x26,0x03,0x1C,0x85,0xDB,0x74,0x09,0x26,0x89,0x1C,0x8B,
-0xF7,0x47,0x47,0x49,0x49,0x80,0xE4,0x1E,0x80,0xCC,0xC0,0x26,0x89,0x04,0xF6,0xC4,
-0x10,0x74,0x27,0x8B,0x76,0x38,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE,0x86,0xB2,
-0x00,0xB0,0x0A,0xE8,0xA8,0xFB,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8,0x68,0x26,
-0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x8B,0xF7,0x33,0xC0,0xAB,0x32,
-0xDB,0x8A,0xBE,0xA3,0x00,0x49,0x49,0x83,0xF9,0x08,0x72,0x17,0xE9,0x41,0xFF,0x81,
-0x4E,0x38,0x00,0x04,0x83,0xC2,0xF8,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,
-0x00,0xEE,0xC3,0xE9,0x45,0xFF,0x83,0xC2,0x08,0xEC,0x88,0x86,0xAA,0x00,0xC0,0xE8,
-0x04,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0x8B,0x5E,0x3E,0x84,0xE3,
-0x74,0x4F,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,0x0C,0xA8,0x08,0x74,0x05,
-0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,0x74,0x0C,0xA8,0x02,0x74,
-0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,0x26,0x8B,0xF0,0x8A,0x86,
-0xA5,0x00,0x84,0xC9,0x74,0x08,0xA8,0x02,0x74,0x15,0x24,0xFD,0xEB,0x06,0xA8,0x02,
-0x75,0x0D,0x0C,0x02,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x83,0xC2,0x0A,0x8B,
-0xC6,0x84,0xE7,0x75,0x01,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8,0xEE,0xFA,
-0xF7,0x46,0x38,0x00,0x02,0x74,0xEE,0x83,0x7E,0x2E,0x06,0x72,0xE8,0x8A,0xA6,0xAA,
-0x00,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,0xB0,0x02,0xAB,0x26,0x83,0x07,
-0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,
-0x4E,0x38,0x20,0xB0,0x00,0xE8,0xB6,0xFA,0xC3,0x90,0x83,0xEA,0x08,0xE9,0xB4,0xFD,
-0x83,0xC2,0x06,0x8B,0x5E,0x26,0xF6,0xC3,0xC0,0x75,0xEF,0x8B,0x4E,0x1C,0xEC,0x88,
-0x86,0xA4,0x00,0x83,0xEA,0x0A,0xA8,0x20,0x75,0x02,0x8A,0xCD,0x32,0xED,0x8B,0x46,
-0x1A,0x3B,0xC8,0x73,0x18,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0xC5,0x76,0x00,
-0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x30,0xC3,0x85,0xC0,0x74,
-0x31,0x8B,0xC8,0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x80,0xCB,0x02,
-0x89,0x5E,0x26,0xE8,0x32,0xF1,0xF6,0xC7,0x01,0x75,0x16,0x83,0xC2,0x02,0xE8,0x53,
-0xFD,0xF6,0xC7,0x10,0x75,0x0B,0xB0,0x02,0xE8,0x43,0xFA,0xC3,0xF6,0xC7,0x01,0x74,
-0xF0,0xC3,0x80,0xCB,0x02,0x89,0x5E,0x26,0xF6,0xC7,0x01,0x74,0xDE,0x83,0xC2,0x02,
-0xE8,0x31,0xFD,0xF6,0x86,0xA4,0x00,0x40,0x74,0x0B,0x80,0xE7,0xFE,0x80,0xCF,0x02,
-0x89,0x5E,0x26,0xEB,0xCC,0xB0,0x04,0xE8,0x14,0xFA,0xC3,0xC0,0xC2,0xC8,0xCA,0xC4,
-0xC6,0xCC,0xCE,0xD0,0xD2,0xD8,0xDA,0xD4,0xD6,0xDC,0xDE,0x90,0xE9,0x0E,0x01,0xE4,
-0xC4,0x8A,0xE0,0xE4,0xC4,0x8B,0xD0,0x83,0xF9,0x08,0x72,0xF0,0x26,0x83,0x3F,0x00,
-0x74,0x04,0x8B,0xDF,0x49,0x49,0x8B,0xFB,0x8A,0xDE,0x83,0xE3,0x0F,0x2E,0x8A,0xA7,
-0x2B,0x16,0xAB,0xF6,0xC4,0x10,0x74,0x24,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE,
-0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xC6,0xF9,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8,
-0x86,0x24,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x89,0x7E,0x04,0x33,
-0xC0,0xAB,0x49,0x49,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x8B,0xC1,0xEB,0x4E,0x90,0xEB,
-0x9E,0x90,0xE4,0xD6,0x84,0xC0,0x79,0x63,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03,
-0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0x8B,0x4E,0x2E,0xC4,
-0x5E,0x04,0x8B,0x7E,0x2C,0x8B,0x76,0x38,0xE4,0x86,0x24,0x07,0x3C,0x03,0x75,0xCF,
-0xE4,0x1C,0x91,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89,0x46,0x2E,0x01,0x4E,
-0x34,0x26,0x01,0x0F,0xBA,0xC4,0x00,0xF3,0x6C,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72,
-0x1C,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8,
-0x3C,0xF9,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD6,0xC3,0xF9,0xC3,0xF7,0xC6,0x0A,
-0x00,0x74,0x35,0xF7,0xC6,0x10,0x00,0x75,0x2F,0x83,0xCE,0x10,0x89,0x76,0x38,0xF7,
-0xC6,0x02,0x00,0x74,0x0E,0x50,0xE4,0xD8,0x24,0xFE,0xE6,0xD8,0x58,0xF7,0xC6,0x08,
-0x00,0x74,0x15,0x50,0x51,0xB9,0xE8,0x03,0xE4,0x0A,0x84,0xC0,0xE0,0xFA,0x84,0xC0,
-0x75,0x04,0xB0,0x24,0xE6,0x0A,0x59,0x58,0x3D,0x40,0x00,0x73,0xB5,0x8A,0x86,0xA5,
-0x00,0x24,0xEF,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0xCE,0x10,0x04,0x89,0x76,0x38,
-0xEB,0xA0,0x00,0x08,0x04,0x0C,0x01,0x09,0x05,0x0D,0x02,0x0A,0x06,0x0E,0x03,0x0B,
-0x07,0x0F,0x00,0x40,0x80,0xC0,0x20,0x60,0xA0,0xE0,0x10,0x50,0x90,0xD0,0x30,0x70,
-0xB0,0xF0,0xE4,0xD2,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,
-0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0xE4,0xD8,0xC0,0xE8,0x04,0x8B,0xD8,0x2E,
-0x8A,0x87,0x62,0x17,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0xE4,0x98,
-0x8B,0x5E,0x3E,0x84,0xE3,0x74,0x54,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,
-0x0C,0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,
-0x74,0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,
-0x26,0x8B,0xF0,0x8A,0x86,0xA5,0x00,0xF6,0xC1,0xFD,0x74,0x08,0xA8,0x06,0x74,0x19,
-0x24,0xF9,0xEB,0x0F,0xA8,0x06,0x75,0x11,0xF6,0xC5,0x01,0x75,0x04,0x0C,0x04,0xEB,
-0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x8B,0xC6,0x84,0xE7,0x75,0x09,0x8A,
-0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD2,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8,
-0x1C,0xF8,0xF7,0x46,0x38,0x00,0x02,0x74,0xE6,0x83,0x7E,0x2E,0x06,0x72,0xE0,0x8A,
-0x86,0xA9,0x00,0x8A,0xE0,0x86,0x86,0xAA,0x00,0x8A,0xC8,0x32,0xC4,0x80,0xC9,0x0B,
-0x22,0xC1,0xC0,0xE4,0x04,0x0A,0xE0,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,
-0xB0,0x02,0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,
-0x38,0x20,0x75,0xAB,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xD1,0xF7,0xEB,0xA0,0x90,
-0xE4,0x12,0x24,0xDF,0xE6,0x12,0x81,0xE3,0xFE,0x9F,0x89,0x5E,0x26,0x83,0x66,0x48,
-0xF7,0xEB,0x73,0x90,0xF6,0xC7,0x20,0x75,0xE7,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,
-0xC0,0xE6,0xC6,0xB0,0x83,0xE6,0xC6,0x80,0xCF,0x20,0x89,0x5E,0x26,0x8A,0x86,0xA5,
-0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xEB,0x74,0x90,0xF6,0xC7,0x40,0x75,
-0xD3,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0,0x81,0xE6,0xC6,0x80,
-0xE7,0xDF,0x80,0xCB,0x01,0x89,0x5E,0x26,0xB0,0x06,0xE8,0x71,0xF7,0x90,0x8A,0x86,
-0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x43,0xE4,0xD4,0xE6,0xD0,
-0x8B,0xF8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x8B,0x5E,
-0x26,0xF6,0xC7,0x60,0x75,0xB6,0xF6,0xC3,0xC0,0x75,0xD3,0xBA,0xC6,0x00,0x8B,0x4E,
-0x1C,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1E,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,
-0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x3D,0x8B,
-0xC7,0x24,0x3F,0xE6,0xD4,0xC3,0x85,0xC0,0x74,0x39,0x8B,0xC8,0x01,0x46,0x2A,0xC5,
-0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x83,0xCB,0x02,0x89,0x5E,0x26,0xE8,0xD9,0xED,0xF6,
-0xC7,0x01,0x75,0x39,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,
-0xF6,0xC7,0x10,0x75,0xCA,0xB0,0x02,0xE8,0xE4,0xF6,0xEB,0xC3,0xF6,0xC7,0x01,0x74,
-0xEF,0xEB,0xBC,0xF6,0xC7,0x01,0x74,0xDC,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x11,
-0x81,0xE3,0xFF,0xFE,0x81,0xCB,0x00,0x02,0x89,0x5E,0x26,0xEB,0xC7,0x8A,0x86,0xA5,
-0x00,0x24,0xFB,0x0C,0x02,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x92,0x90,0xFD,0xF7,
-0xDF,0x7F,0xFE,0xFB,0xEF,0xBF,0x00,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
-0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
-0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
-0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
-0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x03,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
-0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04,
-0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
-0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04,
-0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04,
-0x06,0x04,0x05,0x04,0x05,0x04,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE,
-0xC1,0xE3,0x02,0xE4,0xCE,0xA8,0x04,0x75,0x09,0xA8,0x02,0x74,0x03,0xE9,0x2C,0xFE,
-0xF9,0xC3,0x50,0x53,0xE8,0xCB,0xFC,0x5B,0x58,0xA8,0x02,0x74,0x03,0xE9,0x1C,0xFE,
-0xF8,0xC3,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE,0xC1,0xE3,0x02,0xE9,
-0xD0,0xFB,0x96,0x1A,0xC2,0x1A,0x00,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x0E,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00,
-0x02,0x00,0x04,0x00,0x02,0x00,0xC3,0x90,0xD6,0x14,0x90,0x15,0x58,0x13,0xE2,0x13,
-0xD6,0x1B,0xD6,0x1B,0xE2,0x13,0xD6,0x1B,0x8B,0x94,0x64,0x12,0xC1,0xE6,0x04,0xA8,
-0x01,0x74,0x35,0x50,0x33,0xC0,0x8A,0xC2,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,
-0x8B,0xD8,0x2E,0x8A,0x9F,0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,
-0x28,0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,
-0x97,0xD8,0x1B,0x5E,0x5A,0xEB,0xCD,0x58,0xA8,0x02,0x74,0x36,0x83,0xC6,0x10,0x33,
-0xC0,0x8A,0xC6,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,0x8B,0xD8,0x2E,0x8A,0x9F,
-0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,0x28,0xEC,0xA8,0x01,0x75,
-0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,0x97,0xD8,0x1B,0x5E,0x5A,
-0xEB,0xCD,0xC3,0x90,0x32,0xE4,0x8B,0xD8,0x8B,0xD0,0x2E,0x8A,0x9F,0x96,0x19,0x2E,
-0x22,0x97,0x8E,0x19,0x56,0x52,0x8A,0xC3,0x24,0x03,0x03,0xC6,0x80,0xE3,0x04,0xD0,
-0xEB,0x2E,0xFF,0x97,0xD2,0x1A,0x58,0x5E,0xA9,0x55,0x00,0x75,0xD9,0xC3,0x60,0x1E,
-0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,
-0x33,0xF6,0xE8,0xBF,0xFF,0xEB,0xEE,0x90,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,
-0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,
-0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8,0x94,0xFF,
-0xEB,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,
-0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,
-0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x6B,0xFF,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,
-0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,0x5A,0xFF,0xEB,0xDD,0xA1,0x60,0x12,0xE6,
-0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5C,0x12,0xE6,
-0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,
-0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,
-0x74,0x19,0xBE,0x04,0x00,0xE8,0x1C,0xFF,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,
-0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x0B,0xFF,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,
-0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5E,0x12,0xE6,0xFE,
-0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,
-0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,
-0x33,0xF6,0xE8,0x53,0xFE,0xEB,0xEE,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,
-0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,
-0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x02,0x00,0xE8,0x2C,0xFE,0xEB,0xED,0xB8,0x00,
+0xCC,0x04,0xD0,0x00,0xDA,0x20,0xDC,0x03,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,
+0xCC,0x03,0xCC,0x00,0xD8,0x00,0xCC,0x00,0xD0,0x00,0x00,0x56,0x52,0x1E,0x0E,0x1F,
+0xBE,0x2F,0x09,0x33,0xD2,0xFC,0xAD,0x85,0xC0,0x74,0x0D,0x8A,0xD4,0xEE,0xAD,0x85,
+0xC0,0x74,0x05,0x8A,0xD4,0xEE,0xEB,0xEE,0x1F,0x5A,0x5E,0xC3,0xE4,0x80,0x84,0xC0,
+0x74,0x16,0x78,0x14,0xB0,0x27,0xE6,0xFC,0xB0,0x11,0xE6,0x34,0xE4,0xFC,0x3C,0x27,
+0x75,0x06,0xE4,0x11,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE,
+0x83,0xEA,0x02,0xB0,0x10,0xEE,0x88,0x86,0xAF,0x00,0xB0,0x11,0x83,0xC2,0x04,0xEE,
+0x83,0xC2,0x02,0xEE,0xB0,0x13,0x83,0xC2,0x02,0xEE,0x83,0xC2,0x02,0xEE,0x2E,0xA1,
+0x4C,0x2D,0x89,0x86,0x94,0x00,0x83,0xEA,0x0E,0xEE,0x83,0xC2,0x02,0x8A,0xC4,0xEE,
+0x83,0xC2,0x04,0xB0,0x03,0xEE,0x88,0x86,0xA8,0x00,0x83,0xEA,0x04,0x32,0xC0,0xEE,
+0x83,0xC2,0x02,0xB0,0x89,0xEE,0x88,0x86,0xA6,0x00,0x0C,0x06,0xEE,0xB0,0x40,0xB4,
+0x38,0x89,0x46,0x1C,0xC7,0x46,0x36,0x38,0x00,0x83,0xC2,0x04,0x32,0xC0,0xEE,0x88,
+0x86,0xA7,0x00,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xEC,0x3A,0x86,
+0xAF,0x00,0x75,0x24,0x83,0xC2,0x04,0xEC,0x3C,0x11,0x75,0x1C,0x83,0xC2,0x06,0xEC,
+0x3C,0x13,0x75,0x14,0x83,0xEA,0x08,0x8A,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x02,0xEC,
+0x24,0xC0,0x3C,0xC0,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x33,0xC9,0x8B,0xD1,0x8B,0xF1,
+0x8A,0x0E,0x94,0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,
+0x20,0x74,0x0E,0x8A,0x86,0x9E,0x00,0xE6,0xFE,0x32,0xC0,0xE6,0x80,0x42,0xE8,0xFA,
+0xFE,0x83,0xC6,0x08,0xE2,0xE1,0x85,0xD2,0x74,0x03,0xE8,0x05,0x08,0xC3,0x33,0xC9,
+0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,
+0x74,0x06,0xE8,0x73,0x16,0xE8,0x12,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,
+0xF1,0x8A,0x0E,0x94,0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,
+0x00,0x20,0x74,0x16,0xE8,0x46,0x16,0xE8,0xD2,0xFE,0x73,0x0E,0x6A,0x00,0x1F,0xC6,
+0x06,0x93,0x12,0x1C,0x9C,0x0E,0xE8,0xE3,0x07,0x90,0x83,0xC6,0x08,0xE2,0xD9,0xC3,
+0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,
+0x40,0x00,0x74,0x16,0xE8,0x21,0x16,0xE8,0x2A,0xFF,0x73,0x0E,0x6A,0x00,0x1F,0xC6,
+0x06,0x93,0x12,0x1C,0x9C,0x0E,0xE8,0xB3,0x07,0x90,0x46,0x46,0xE2,0xDA,0xC3,0x0C,
+0x00,0x00,0x10,0x00,0x13,0x12,0x00,0x00,0x14,0x00,0x28,0x3C,0x00,0x1B,0x3E,0x00,
+0x00,0x2A,0x00,0x00,0x2C,0x00,0x00,0x42,0x00,0x14,0xD8,0x00,0x00,0xDA,0x00,0x00,
+0x34,0x00,0x11,0x36,0x00,0x13,0x38,0x00,0x11,0x3A,0x00,0x13,0x00,0x00,0x56,0x50,
+0x52,0xBE,0x2F,0x0B,0x2E,0xAD,0x85,0xC0,0x74,0x06,0x92,0x2E,0xAC,0xEE,0xEB,0xF4,
+0x5A,0x58,0x5E,0xC3,0x53,0x2E,0xA1,0x60,0x22,0xE6,0xE4,0xE6,0xF0,0x8A,0xC4,0xE6,
+0xEC,0xE6,0xF8,0xE8,0xD8,0xFF,0xB0,0x4B,0xE6,0x10,0xB0,0x50,0xE6,0x12,0xB0,0x38,
+0xE6,0x14,0xE8,0xAE,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0xA7,0x15,0xB0,0x1A,0xE6,0x0A,
+0xE8,0xA0,0x15,0xB0,0x22,0xE6,0x0A,0xE8,0x99,0x15,0xE8,0xFD,0x06,0x8B,0xD8,0xE4,
+0x16,0xA8,0x04,0x75,0x18,0xE8,0xF2,0x06,0x2B,0xC3,0x3D,0x32,0x00,0x72,0xF0,0x6A,
+0x00,0x1F,0xC6,0x06,0x93,0x12,0x23,0x9C,0x0E,0xE8,0x10,0x07,0x90,0xE8,0xDA,0x06,
+0x2B,0xC3,0x3D,0x24,0x00,0x77,0x1B,0xB0,0x31,0xE6,0xFC,0x56,0x51,0x55,0xB9,0x10,
+0x00,0x2E,0x8B,0xAC,0x44,0x00,0x81,0x4E,0x38,0x80,0x00,0x46,0x46,0xE2,0xF2,0x5D,
+0x59,0x5E,0xE8,0x69,0xFF,0xE8,0x4B,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0x44,0x15,0x5B,
+0xC3,0x33,0xF6,0x8B,0x0E,0x42,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,
+0x20,0x74,0x06,0xE8,0x17,0x15,0xE8,0x5B,0xFF,0x83,0xC6,0x20,0xE2,0xE9,0xC3,0x8B,
+0xC2,0x05,0x04,0x00,0x89,0x46,0x28,0x2E,0xA1,0x4C,0x2D,0x89,0x86,0x8E,0x00,0x89,
+0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xC6,0x86,0xA3,0x00,0x0A,0xC6,0x86,0xC3,0x00,
+0x03,0x52,0x83,0xC2,0x04,0x8A,0x86,0xA6,0x00,0x0C,0x06,0xEE,0x5A,0x83,0xC2,0x02,
+0xB0,0x05,0xEE,0x88,0x86,0xA5,0x00,0xC3,0xE8,0x03,0xFF,0xE8,0xE5,0x14,0xB0,0x42,
+0xE6,0x0A,0xF7,0x46,0x38,0x80,0x00,0x74,0x06,0x2E,0xA1,0x9C,0x22,0xEB,0x04,0x2E,
+0xA1,0x6C,0x22,0xC7,0x46,0x1C,0x0C,0x00,0x89,0x86,0x94,0x00,0x89,0x86,0x96,0x00,
+0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xE6,0xF0,0xE6,0xE4,
+0x8A,0xC4,0xE6,0xF8,0xE6,0xEC,0xC6,0x86,0xC3,0x00,0x03,0xE8,0xA5,0x14,0xB0,0x1A,
+0xE6,0x0A,0xB0,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,
+0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,
+0x76,0x14,0xE8,0x5A,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,
+0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,0x4C,
+0x14,0xE8,0x74,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x90,0x83,0x3E,0x44,0x12,0x00,0x75,
+0x14,0xB0,0x01,0xBA,0x06,0x01,0xEE,0x2A,0xC0,0xEE,0xB0,0x02,0xEE,0xB0,0x04,0xEE,
+0xB8,0x00,0x02,0xEB,0x0F,0xBA,0x06,0x01,0xB0,0x40,0xEE,0xB8,0x01,0x00,0x8A,0x0E,
+0x0E,0x01,0xD3,0xE0,0xA3,0x88,0x12,0xC3,0xA1,0x88,0x12,0xA3,0x84,0x12,0x2D,0x20,
+0x00,0xA3,0x8A,0x12,0x2D,0x20,0x00,0xA3,0x82,0x12,0xC7,0x06,0x86,0x12,0x20,0x00,
+0xC7,0x06,0x80,0x12,0x32,0x00,0xC3,0x83,0x3E,0x44,0x12,0x00,0x74,0x76,0x8B,0x0E,
+0x42,0x12,0x33,0xF6,0x8A,0xA4,0x54,0x12,0x84,0xE4,0x74,0x5F,0x8A,0x84,0x48,0x12,
+0x0C,0x04,0xE6,0xFE,0xF6,0xC4,0x04,0x74,0x25,0xB0,0x1B,0xBA,0x00,0x00,0xEE,0xEB,
+0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0x32,0xC0,
+0xBA,0x02,0x00,0xEE,0xEB,0x00,0xBA,0x00,0x00,0xB0,0x00,0xEE,0xEB,0x2D,0xB0,0x1F,
+0xBA,0x00,0x00,0xEE,0xEB,0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,
+0xEE,0xEB,0x00,0xD1,0xE6,0x8A,0x84,0x5D,0x12,0xD1,0xEE,0xF6,0xD0,0xBA,0x02,0x00,
+0xEE,0xEB,0x00,0xBA,0x00,0x00,0xB0,0x0A,0xEE,0xEB,0x00,0xE4,0x04,0xEB,0x00,0xE4,
+0x04,0x46,0xE2,0x90,0xC3,0x90,0xB8,0x14,0x00,0xBA,0x3E,0xFF,0xEF,0xB8,0x06,0x00,
+0xBA,0x32,0xFF,0xEF,0xB8,0x0F,0x00,0xBA,0x34,0xFF,0xEF,0xBA,0x36,0xFF,0xEF,0x83,
+0x3E,0x44,0x12,0x00,0x75,0x16,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,0x12,0x00,
+0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0x11,0x00,0xBA,
+0x38,0xFF,0xEF,0xB8,0x12,0x00,0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF,
+0xEF,0xC3,0xB8,0xFC,0x00,0xBA,0x28,0xFF,0xEF,0xFB,0x83,0x3E,0x44,0x12,0x00,0x74,
+0x07,0xB8,0xCC,0x00,0xBA,0x28,0xFF,0xEF,0xC3,0x00,0xFF,0xFF,0x20,0x24,0x28,0xFF,
+0x2C,0xFF,0xFF,0x30,0x34,0x38,0xFF,0xFF,0x3C,0x90,0x3C,0x0F,0x77,0x0E,0xBB,0x19,
+0x0E,0x2E,0xD7,0x3C,0xFF,0x74,0x05,0x8A,0xD8,0xF8,0xC3,0x90,0x2A,0xDB,0xF9,0xC3,
+0x83,0x3E,0x44,0x12,0x00,0x74,0x27,0xA0,0x06,0x01,0x80,0x26,0x06,0x01,0x30,0x80,
+0x3E,0x06,0x01,0x30,0x75,0x18,0xB9,0x02,0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC,
+0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xED,0xAB,0xE2,0xF1,0xEB,0x16,0x90,0xB9,0x04,
+0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xEC,
+0xAA,0xE2,0xF1,0xFA,0x90,0xBE,0xC4,0x13,0xAD,0x80,0xE4,0x3F,0x80,0xFC,0x02,0x74,
+0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x0A,0x9C,0x0E,0xE8,0x3E,0x04,0x90,0xAD,
+0x3C,0x0F,0x75,0xED,0x8A,0xC4,0xE8,0x81,0xFF,0x72,0xE6,0x88,0x1E,0x1A,0x01,0xC6,
+0x06,0x8E,0x12,0x00,0xB0,0x00,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xC6,0x06,
+0x8F,0x12,0x40,0x83,0x3E,0x44,0x12,0x00,0x75,0x06,0xB8,0x0C,0x00,0xEB,0x04,0x90,
+0xB8,0x4C,0x00,0xBA,0x28,0xFF,0xEF,0xC3,0x83,0x3E,0x44,0x12,0x00,0x75,0x01,0xC3,
+0xA1,0x50,0x12,0x0B,0x06,0x52,0x12,0x0A,0xC4,0xA8,0x08,0x74,0xF2,0xA0,0x0F,0x01,
+0x2A,0xE4,0x50,0xFF,0x36,0xBA,0x13,0x1F,0xE8,0x50,0x56,0x83,0xC4,0x02,0x6A,0x00,
+0x1F,0x33,0xC0,0xA3,0xBC,0x13,0xA0,0x0F,0x01,0xA3,0xBE,0x13,0x8B,0x1E,0xBC,0x13,
+0x8A,0x87,0x50,0x12,0xF6,0x87,0x50,0x12,0x08,0x74,0x0D,0x24,0x07,0x8A,0xE0,0xBE,
+0xCC,0x00,0xA0,0xBC,0x13,0xE8,0x94,0x3D,0xFF,0x06,0xBC,0x13,0xFF,0x0E,0xBE,0x13,
+0x75,0xDA,0xC3,0x90,0x1E,0x33,0xC0,0x8E,0xD8,0xB0,0x01,0xE8,0x54,0x3D,0x1F,0xC3,
+0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xC7,0x46,0x62,
+0x38,0x44,0xC7,0x46,0x7C,0xFC,0x3B,0xC7,0x46,0x7E,0xE2,0x3B,0xC7,0x86,0x80,0x00,
+0xEC,0x3C,0xE8,0xAB,0x16,0xC6,0x86,0xC0,0x00,0x11,0x83,0x7E,0x08,0x00,0x74,0x07,
+0x51,0x56,0xE8,0x33,0x33,0x5E,0x59,0x46,0x46,0xE2,0xCD,0xC3,0x33,0xC9,0x8B,0xF1,
+0x8B,0xF9,0x8A,0x0E,0x94,0x12,0xC1,0xE9,0x02,0xE3,0x13,0x2E,0x8B,0xAC,0x44,0x00,
+0x8A,0x86,0x9E,0x00,0x88,0x85,0x6C,0x12,0x83,0xC6,0x08,0x47,0xE2,0xED,0xC3,0xFA,
+0xFC,0xB0,0xC0,0xBA,0x00,0x01,0xEE,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,0xBF,
+0x16,0x01,0xB9,0xCC,0x77,0x2B,0xCF,0xD1,0xE9,0xF3,0xAB,0xBC,0x40,0x12,0xE8,0xD9,
+0x02,0xE8,0x70,0x3C,0xBE,0xCC,0x0F,0xE8,0xF2,0x3C,0xF4,0x90,0x33,0xC0,0x8E,0xD8,
+0x8E,0xC0,0x8E,0xD0,0xF6,0x06,0x0A,0x01,0x80,0x74,0x0B,0xBE,0x35,0x55,0xE8,0xDB,
+0x3C,0xB0,0x01,0xE8,0xAC,0x3C,0xE8,0xB3,0x00,0xE8,0xF6,0xF5,0xE8,0x08,0xF8,0xE8,
+0x0F,0xF9,0xE8,0x85,0xFA,0xE8,0xB6,0xFA,0xE8,0xEF,0xFC,0xE8,0xC2,0x10,0xE8,0x03,
+0x3C,0xE8,0xB2,0xFD,0xE8,0x30,0xFD,0xE8,0x54,0x02,0xC6,0x06,0x8F,0x12,0xC0,0xE8,
+0xBB,0xFA,0xE8,0xEB,0xFA,0xE8,0xE9,0xFB,0xE8,0xAF,0xFC,0xE8,0x8D,0xFC,0xE8,0x1F,
+0xFF,0xE8,0x58,0xFF,0xE8,0xDB,0xFD,0xE8,0x16,0xFE,0x33,0xC0,0xBE,0x5A,0x05,0xE8,
+0x8A,0x3C,0xE8,0xA3,0xFE,0xE8,0xE0,0xFC,0xFB,0xBE,0xA4,0x44,0xE8,0x7D,0x3C,0xE9,
+0xCA,0x2D,0x56,0x98,0x8B,0xF0,0x8B,0x42,0x52,0x85,0xC0,0x75,0x27,0xC7,0x42,0x52,
+0x01,0x00,0x53,0x36,0x8B,0x9C,0x2C,0x01,0xF6,0xC3,0x01,0x75,0x0C,0x36,0x89,0x68,
+0x52,0x36,0x89,0xAC,0x2C,0x01,0x5B,0x5E,0xC3,0x36,0x89,0xAC,0x2C,0x01,0x36,0x89,
+0xAC,0x1C,0x01,0x5B,0x5E,0xC3,0x56,0x98,0x8B,0xF0,0x33,0xED,0x36,0x8B,0x84,0x1C,
+0x01,0xA8,0x01,0x75,0x15,0x8B,0xE8,0x33,0xC0,0x87,0x42,0x52,0x36,0x89,0x84,0x1C,
+0x01,0xA8,0x01,0x74,0x05,0x36,0x89,0x84,0x2C,0x01,0x5E,0xC3,0x56,0x51,0x33,0xF6,
+0xB8,0x01,0x00,0xB9,0x08,0x00,0x89,0x84,0x1C,0x01,0x89,0x84,0x2C,0x01,0x46,0x46,
+0xE2,0xF4,0x59,0x5E,0xC3,0x90,0xBB,0x01,0x00,0x8B,0xE8,0xFF,0x4E,0x6E,0x74,0x0A,
+0x8B,0xDD,0x8B,0x46,0x58,0xA8,0x01,0x74,0xF0,0xC3,0x8B,0x46,0x48,0xA9,0x08,0x00,
+0x74,0x45,0xF7,0x46,0x38,0x40,0x00,0x74,0x27,0xE8,0x5C,0x10,0x80,0xC2,0x06,0x8A,
+0x86,0xA8,0x00,0x24,0xBF,0x88,0x86,0xA8,0x00,0xEE,0x60,0xB0,0xFE,0xE8,0x86,0x32,
+0x61,0xB0,0x02,0xE8,0x4C,0xFF,0x8B,0x46,0x48,0x24,0xF7,0x89,0x46,0x48,0xEB,0x17,
+0xE8,0x2A,0x10,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,
+0xA5,0x00,0xE6,0x0C,0x8B,0x46,0x48,0xA9,0x04,0x00,0x74,0x14,0xB0,0x02,0xE8,0x21,
+0xFF,0x8B,0x46,0x48,0x24,0xFB,0x89,0x46,0x48,0x60,0xB0,0xDF,0xE8,0x47,0x32,0x61,
+0x33,0xC0,0x87,0x46,0x58,0xF6,0xC3,0x01,0x75,0x0B,0x36,0x89,0x47,0x58,0xA8,0x01,
+0x75,0x0D,0xE9,0x74,0xFF,0xA3,0x22,0x01,0xA8,0x01,0x75,0x03,0xE9,0x6A,0xFF,0x89,
+0x1E,0x32,0x01,0xC3,0xBB,0x01,0x00,0x8B,0xE8,0xF7,0x46,0x38,0x40,0x00,0x74,0x15,
+0xE8,0xD5,0x0F,0x80,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x0A,0x8B,0xDD,0x8B,0x46,0x56,
+0xA8,0x01,0x74,0xE3,0xC3,0x8B,0x46,0x26,0x80,0xE4,0xFE,0x80,0xCC,0x02,0x89,0x46,
+0x26,0xB0,0x02,0xE8,0xBC,0xFE,0x33,0xC0,0x87,0x46,0x56,0xF6,0xC3,0x01,0x75,0x0A,
+0x36,0x89,0x47,0x56,0xA8,0x01,0x75,0x0B,0xEB,0xBD,0xA3,0x20,0x01,0xA8,0x01,0x75,
+0x02,0xEB,0xB4,0x89,0x1E,0x30,0x01,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA0,
+0x90,0x12,0x84,0xC0,0x75,0x49,0xA1,0x22,0x01,0xA8,0x01,0x75,0x03,0xE8,0xF6,0xFE,
+0xA1,0x20,0x01,0xA8,0x01,0x75,0x03,0xE8,0x8A,0xFF,0xA1,0xAC,0x13,0x48,0x78,0x05,
+0x74,0x45,0xA3,0xAC,0x13,0xA1,0xAE,0x13,0x48,0x78,0x05,0x74,0x51,0xA3,0xAE,0x13,
+0xA1,0xB0,0x13,0x48,0x78,0x05,0x74,0x63,0xA3,0xB0,0x13,0xA1,0x7E,0x12,0x40,0x78,
+0x03,0xA3,0x7E,0x12,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0xA0,
+0x91,0x12,0x40,0x3C,0x02,0x72,0x0B,0x33,0xC0,0xA2,0x91,0x12,0xFF,0x16,0x7C,0x12,
+0xEB,0xA4,0xA2,0x91,0x12,0xEB,0x9F,0xA0,0x8E,0x12,0x32,0x06,0x8F,0x12,0xA2,0x8E,
+0x12,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xB8,0x2C,0x01,0xEB,0xA4,0x83,0x3E,
+0x84,0x12,0x10,0x72,0x11,0xBA,0x28,0xFF,0xED,0x0C,0x81,0xEF,0xE8,0x53,0x37,0xBA,
+0x28,0xFF,0xED,0x24,0x7E,0xEF,0xB8,0x04,0x00,0xEB,0x92,0xC6,0x06,0x8D,0x12,0x01,
+0xE8,0x3F,0x37,0xC6,0x06,0x8D,0x12,0x00,0xA1,0xB2,0x13,0xEB,0x8B,0x90,0x8A,0x1E,
+0x0B,0x01,0x2A,0xFF,0x6B,0xC3,0x19,0xBA,0x62,0xFF,0xEF,0xB8,0x0A,0x00,0xBA,0x60,
+0xFF,0xEF,0xB8,0x01,0xE0,0xBA,0x66,0xFF,0xEF,0xB8,0xFF,0xFF,0xBA,0x52,0xFF,0xEF,
+0xB8,0x09,0xC0,0xBA,0x56,0xFF,0xEF,0xC7,0x06,0xAC,0x13,0x2C,0x01,0xC7,0x06,0xAE,
+0x13,0x04,0x00,0xC6,0x06,0x91,0x12,0x00,0xC3,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF,
+0x6B,0xC3,0x05,0xD1,0xE8,0xA3,0x18,0x01,0xC3,0x90,0x52,0xBA,0x50,0xFF,0xED,0x5A,
+0xC3,0x90,0x53,0x51,0x8B,0x1E,0x18,0x01,0xB9,0x32,0x05,0x90,0xE2,0xFE,0x4B,0x75,
+0xF7,0x59,0x5B,0xC3,0xB0,0x80,0xBA,0x00,0x01,0x0A,0x06,0x1A,0x01,0xEE,0xC3,0x90,
+0xB0,0x40,0xEB,0xF2,0xB0,0xC0,0xEB,0xEE,0xB0,0x00,0xEB,0xEA,0xFA,0x60,0x06,0x1E,
+0x16,0x2B,0xDB,0x8E,0xDB,0x2E,0xA1,0xBA,0x4C,0x2E,0xA3,0x92,0x4C,0xA0,0x93,0x12,
+0x98,0x8B,0xE8,0x89,0x26,0x2D,0x7A,0x80,0x3E,0xCA,0x13,0x00,0x74,0x03,0xE9,0x6B,
+0x42,0xE8,0xC0,0xFF,0xE8,0xAB,0xFF,0xE8,0xA8,0xFF,0xB0,0x20,0xC6,0x06,0x90,0x12,
+0x00,0xFF,0x16,0x7C,0x12,0x8B,0xFD,0x83,0xFF,0x0A,0x72,0x11,0xE8,0xB9,0xFF,0xE8,
+0x90,0xFF,0xE8,0xAB,0xFF,0xE8,0x8A,0xFF,0x83,0xEF,0x0A,0xEB,0xEA,0x0B,0xFF,0x74,
+0x0F,0xE8,0xA4,0xFF,0xE8,0x7B,0xFF,0xE8,0x9A,0xFF,0xE8,0x75,0xFF,0x4F,0x75,0xF1,
+0xE8,0x95,0xFF,0xE8,0x6C,0xFF,0xEB,0xB9,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88,
+0x86,0xA5,0x00,0xC3,0x8A,0x86,0xA6,0x00,0x0C,0x02,0xEE,0xC3,0x8B,0x76,0x38,0xF7,
+0xC6,0x01,0x00,0x74,0xEF,0x8B,0x4E,0x36,0x8B,0x46,0x2E,0x3B,0xC1,0x73,0x02,0x8B,
+0xC8,0x2B,0xC1,0x89,0x46,0x2E,0x01,0x4E,0x34,0xC4,0x7E,0x04,0x26,0x01,0x0D,0x8B,
+0x7E,0x2C,0x83,0xEA,0x04,0xF3,0x6C,0x8E,0xC1,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72,
+0x12,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8,
+0xA0,0xFC,0xC3,0xF7,0xC6,0x04,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xCE,0x10,0x89,0x76,
+0x38,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xC2,0x08,0xEE,0x83,
+0xEA,0x08,0x8B,0xC3,0x3D,0x40,0x00,0x72,0x01,0xC3,0x81,0x4E,0x38,0x00,0x04,0x83,
+0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0x8A,0x86,
+0xA6,0x00,0x0C,0x02,0xEE,0xC3,0xF7,0x46,0x38,0x01,0x00,0x74,0xF1,0x8B,0x4E,0x2E,
+0x32,0xDB,0x8A,0xBE,0xA3,0x00,0x83,0xC2,0x06,0xC4,0x76,0x04,0x8B,0x7E,0x2C,0x83,
+0xF9,0x08,0x72,0x2C,0xEC,0xA8,0x01,0x74,0x16,0x8A,0xE0,0x83,0xEA,0x0A,0xEC,0x83,
+0xC2,0x0A,0x84,0xE7,0x75,0x51,0xAA,0xFE,0xC3,0x49,0x83,0xF9,0x08,0x73,0xE5,0x32,
+0xFF,0x26,0x01,0x1C,0x01,0x5E,0x34,0x89,0x76,0x04,0x89,0x4E,0x2E,0x89,0x7E,0x2C,
+0x3B,0x4E,0x3C,0x72,0x11,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,0x4E,0x38,0x20,
+0xB0,0x00,0xE8,0xFD,0xFB,0xC3,0xF6,0x46,0x38,0x04,0x74,0x15,0x83,0x4E,0x38,0x10,
+0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x02,0xEE,0x83,0xC2,
+0x02,0x3D,0x40,0x00,0x72,0x5D,0xC3,0x32,0xFF,0x26,0x03,0x1C,0x85,0xDB,0x74,0x09,
+0x26,0x89,0x1C,0x8B,0xF7,0x47,0x47,0x49,0x49,0x80,0xE4,0x1E,0x80,0xCC,0xC0,0x26,
+0x89,0x04,0xF6,0xC4,0x10,0x74,0x27,0x8B,0x76,0x38,0xF7,0xC6,0x00,0x10,0x74,0x0B,
+0x50,0xFE,0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xA8,0xFB,0x58,0xF7,0xC6,0x00,0x01,0x74,
+0x0D,0xE8,0x82,0x26,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x8B,0xF7,
+0x33,0xC0,0xAB,0x32,0xDB,0x8A,0xBE,0xA3,0x00,0x49,0x49,0x83,0xF9,0x08,0x72,0x17,
+0xE9,0x41,0xFF,0x81,0x4E,0x38,0x00,0x04,0x83,0xC2,0xF8,0x8A,0x86,0xA5,0x00,0x24,
+0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0xE9,0x45,0xFF,0x83,0xC2,0x08,0xEC,0x88,0x86,
+0xAA,0x00,0xC0,0xE8,0x04,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0x8B,
+0x5E,0x3E,0x84,0xE3,0x74,0x4F,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,0x0C,
+0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,0x74,
+0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,0x26,
+0x8B,0xF0,0x8A,0x86,0xA5,0x00,0x84,0xC9,0x74,0x08,0xA8,0x02,0x74,0x15,0x24,0xFD,
+0xEB,0x06,0xA8,0x02,0x75,0x0D,0x0C,0x02,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,
+0x83,0xC2,0x0A,0x8B,0xC6,0x84,0xE7,0x75,0x01,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,
+0x0E,0xE8,0xEE,0xFA,0xF7,0x46,0x38,0x00,0x02,0x74,0xEE,0x83,0x7E,0x2E,0x06,0x72,
+0xE8,0x8A,0xA6,0xAA,0x00,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,0xB0,0x02,
+0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,0x38,0x20,
+0x74,0x01,0xC3,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xB6,0xFA,0xC3,0x90,0x83,0xEA,
+0x08,0xE9,0xB4,0xFD,0x83,0xC2,0x06,0x8B,0x5E,0x26,0xF6,0xC3,0xC0,0x75,0xEF,0x8B,
+0x4E,0x1C,0xEC,0x88,0x86,0xA4,0x00,0x83,0xEA,0x0A,0xA8,0x20,0x75,0x02,0x8A,0xCD,
+0x32,0xED,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x18,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,
+0x1A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x30,
+0xC3,0x85,0xC0,0x74,0x31,0x8B,0xC8,0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,
+0xD9,0x80,0xCB,0x02,0x89,0x5E,0x26,0xE8,0x32,0xF1,0xF6,0xC7,0x01,0x75,0x16,0x83,
+0xC2,0x02,0xE8,0x53,0xFD,0xF6,0xC7,0x10,0x75,0x0B,0xB0,0x02,0xE8,0x43,0xFA,0xC3,
+0xF6,0xC7,0x01,0x74,0xF0,0xC3,0x80,0xCB,0x02,0x89,0x5E,0x26,0xF6,0xC7,0x01,0x74,
+0xDE,0x83,0xC2,0x02,0xE8,0x31,0xFD,0xF6,0x86,0xA4,0x00,0x40,0x74,0x0B,0x80,0xE7,
+0xFE,0x80,0xCF,0x02,0x89,0x5E,0x26,0xEB,0xCC,0xB0,0x04,0xE8,0x14,0xFA,0xC3,0xC0,
+0xC2,0xC8,0xCA,0xC4,0xC6,0xCC,0xCE,0xD0,0xD2,0xD8,0xDA,0xD4,0xD6,0xDC,0xDE,0x90,
+0xE9,0x0E,0x01,0xE4,0xC4,0x8A,0xE0,0xE4,0xC4,0x8B,0xD0,0x83,0xF9,0x08,0x72,0xF0,
+0x26,0x83,0x3F,0x00,0x74,0x04,0x8B,0xDF,0x49,0x49,0x8B,0xFB,0x8A,0xDE,0x83,0xE3,
+0x0F,0x2E,0x8A,0xA7,0x2F,0x16,0xAB,0xF6,0xC4,0x10,0x74,0x24,0xF7,0xC6,0x00,0x10,
+0x74,0x0B,0x50,0xFE,0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xC6,0xF9,0x58,0xF7,0xC6,0x00,
+0x01,0x74,0x0D,0xE8,0xA0,0x24,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,
+0x89,0x7E,0x04,0x33,0xC0,0xAB,0x49,0x49,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x8B,0xC1,
+0xEB,0x4E,0x90,0xEB,0x9E,0x90,0xE4,0xD6,0x84,0xC0,0x79,0x63,0xE6,0xD0,0x8A,0xC8,
+0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,
+0x8B,0x4E,0x2E,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0x8B,0x76,0x38,0xE4,0x86,0x24,0x07,
+0x3C,0x03,0x75,0xCF,0xE4,0x1C,0x91,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89,
+0x46,0x2E,0x01,0x4E,0x34,0x26,0x01,0x0F,0xBA,0xC4,0x00,0xF3,0x6C,0x89,0x7E,0x2C,
+0x3B,0x46,0x3C,0x72,0x1C,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,
+0x38,0xB0,0x00,0xE8,0x3C,0xF9,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD6,0xC3,0xF9,
+0xC3,0xF7,0xC6,0x0A,0x00,0x74,0x35,0xF7,0xC6,0x10,0x00,0x75,0x2F,0x83,0xCE,0x10,
+0x89,0x76,0x38,0xF7,0xC6,0x02,0x00,0x74,0x0E,0x50,0xE4,0xD8,0x24,0xFE,0xE6,0xD8,
+0x58,0xF7,0xC6,0x08,0x00,0x74,0x15,0x50,0x51,0xB9,0xE8,0x03,0xE4,0x0A,0x84,0xC0,
+0xE0,0xFA,0x84,0xC0,0x75,0x04,0xB0,0x24,0xE6,0x0A,0x59,0x58,0x3D,0x40,0x00,0x73,
+0xB5,0x8A,0x86,0xA5,0x00,0x24,0xEF,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0xCE,0x10,
+0x04,0x89,0x76,0x38,0xEB,0xA0,0x00,0x08,0x04,0x0C,0x01,0x09,0x05,0x0D,0x02,0x0A,
+0x06,0x0E,0x03,0x0B,0x07,0x0F,0x00,0x40,0x80,0xC0,0x20,0x60,0xA0,0xE0,0x10,0x50,
+0x90,0xD0,0x30,0x70,0xB0,0xF0,0xE4,0xD2,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03,
+0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0xE4,0xD8,0xC0,0xE8,
+0x04,0x8B,0xD8,0x2E,0x8A,0x87,0x66,0x17,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,
+0x32,0xE0,0xE4,0x98,0x8B,0x5E,0x3E,0x84,0xE3,0x74,0x54,0x8A,0xC1,0x8B,0x4E,0x26,
+0xF6,0xC5,0x04,0x74,0x0C,0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,
+0x40,0xF6,0xC5,0x08,0x74,0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,
+0xC9,0x80,0x88,0x4E,0x26,0x8B,0xF0,0x8A,0x86,0xA5,0x00,0xF6,0xC1,0xFD,0x74,0x08,
+0xA8,0x06,0x74,0x19,0x24,0xF9,0xEB,0x0F,0xA8,0x06,0x75,0x11,0xF6,0xC5,0x01,0x75,
+0x04,0x0C,0x04,0xEB,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x8B,0xC6,0x84,
+0xE7,0x75,0x09,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD2,0xC3,0xC6,0x86,0xBA,0x00,
+0x01,0xB0,0x0E,0xE8,0x1C,0xF8,0xF7,0x46,0x38,0x00,0x02,0x74,0xE6,0x83,0x7E,0x2E,
+0x06,0x72,0xE0,0x8A,0x86,0xA9,0x00,0x8A,0xE0,0x86,0x86,0xAA,0x00,0x8A,0xC8,0x32,
+0xC4,0x80,0xC9,0x0B,0x22,0xC1,0xC0,0xE4,0x04,0x0A,0xE0,0xC4,0x5E,0x04,0x8B,0x7E,
+0x2C,0xB0,0xFF,0xAA,0xB0,0x02,0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89,
+0x7E,0x2C,0xF6,0x46,0x38,0x20,0x75,0xAB,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xD1,
+0xF7,0xEB,0xA0,0x90,0xE4,0x12,0x24,0xDF,0xE6,0x12,0x81,0xE3,0xFE,0x9F,0x89,0x5E,
+0x26,0x83,0x66,0x48,0xF7,0xEB,0x73,0x90,0xF6,0xC7,0x20,0x75,0xE7,0xE4,0x12,0x0C,
+0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0,0x83,0xE6,0xC6,0x80,0xCF,0x20,0x89,0x5E,
+0x26,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xEB,0x74,0x90,
+0xF6,0xC7,0x40,0x75,0xD3,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0,
+0x81,0xE6,0xC6,0x80,0xE7,0xDF,0x80,0xCB,0x01,0x89,0x5E,0x26,0xB0,0x06,0xE8,0x71,
+0xF7,0x90,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x43,
+0xE4,0xD4,0xE6,0xD0,0x8B,0xF8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,
+0x44,0x00,0x8B,0x5E,0x26,0xF6,0xC7,0x60,0x75,0xB6,0xF6,0xC3,0xC0,0x75,0xD3,0xBA,
+0xC6,0x00,0x8B,0x4E,0x1C,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1E,0x01,0x4E,0x2A,0x2B,
+0xC1,0x89,0x46,0x1A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,
+0x00,0x72,0x3D,0x8B,0xC7,0x24,0x3F,0xE6,0xD4,0xC3,0x85,0xC0,0x74,0x39,0x8B,0xC8,
+0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x83,0xCB,0x02,0x89,0x5E,0x26,
+0xE8,0xD9,0xED,0xF6,0xC7,0x01,0x75,0x39,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C,
+0x88,0x86,0xA5,0x00,0xF6,0xC7,0x10,0x75,0xCA,0xB0,0x02,0xE8,0xE4,0xF6,0xEB,0xC3,
+0xF6,0xC7,0x01,0x74,0xEF,0xEB,0xBC,0xF6,0xC7,0x01,0x74,0xDC,0x8A,0x86,0xA5,0x00,
+0xA8,0x02,0x74,0x11,0x81,0xE3,0xFF,0xFE,0x81,0xCB,0x00,0x02,0x89,0x5E,0x26,0xEB,
+0xC7,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,
+0x92,0x90,0xFD,0xF7,0xDF,0x7F,0xFE,0xFB,0xEF,0xBF,0x00,0x04,0x00,0x04,0x05,0x04,
+0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,
+0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,
+0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,
+0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x03,0x04,0x00,0x04,0x05,0x04,
+0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,
+0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,
+0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,
+0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,
+0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x33,0xDB,0x8A,0xD8,0x8A,0x87,
+0x6C,0x12,0xE6,0xFE,0xC1,0xE3,0x02,0xE4,0xCE,0xA8,0x04,0x75,0x09,0xA8,0x02,0x74,
+0x03,0xE9,0x2C,0xFE,0xF9,0xC3,0x50,0x53,0xE8,0xCB,0xFC,0x5B,0x58,0xA8,0x02,0x74,
+0x03,0xE9,0x1C,0xFE,0xF8,0xC3,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE,
+0xC1,0xE3,0x02,0xE9,0xD0,0xFB,0x9A,0x1A,0xC6,0x1A,0x00,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0E,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,
+0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0xC3,0x90,0xDA,0x14,0x94,0x15,
+0x5C,0x13,0xE6,0x13,0xDA,0x1B,0xDA,0x1B,0xE6,0x13,0xDA,0x1B,0x8B,0x94,0x64,0x12,
+0xC1,0xE6,0x04,0xA8,0x01,0x74,0x35,0x50,0x33,0xC0,0x8A,0xC2,0xE6,0xFE,0xE4,0xA0,
+0x85,0xC0,0x74,0x27,0x8B,0xD8,0x2E,0x8A,0x9F,0xDA,0x1A,0x52,0x56,0x2E,0x8B,0xA8,
+0x44,0x00,0x8B,0x56,0x28,0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,
+0x8A,0xD8,0x2E,0xFF,0x97,0xDC,0x1B,0x5E,0x5A,0xEB,0xCD,0x58,0xA8,0x02,0x74,0x36,
+0x83,0xC6,0x10,0x33,0xC0,0x8A,0xC6,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,0x8B,
+0xD8,0x2E,0x8A,0x9F,0xDA,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,0x28,
+0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,0x97,
+0xDC,0x1B,0x5E,0x5A,0xEB,0xCD,0xC3,0x90,0x32,0xE4,0x8B,0xD8,0x8B,0xD0,0x2E,0x8A,
+0x9F,0x9A,0x19,0x2E,0x22,0x97,0x92,0x19,0x56,0x52,0x8A,0xC3,0x24,0x03,0x03,0xC6,
+0x80,0xE3,0x04,0xD0,0xEB,0x2E,0xFF,0x97,0xD6,0x1A,0x58,0x5E,0xA9,0x55,0x00,0x75,
+0xD9,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,
+0x22,0xC4,0x74,0x08,0x33,0xF6,0xE8,0xBF,0xFF,0xEB,0xEE,0x90,0xE4,0x04,0x07,0xE4,
+0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,
+0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,0xBE,0x04,
+0x00,0xE8,0x94,0xFF,0xEB,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,
+0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,
+0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x6B,0xFF,0xA1,0x60,0x12,
+0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,0x5A,0xFF,0xEB,0xDD,
+0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,
+0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,
+0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,
+0xE4,0x00,0x22,0xC4,0x74,0x19,0xBE,0x04,0x00,0xE8,0x1C,0xFF,0xA1,0x62,0x12,0xE6,
+0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x0B,0xFF,0xEB,0xDC,0xA1,
+0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,
+0x5E,0x12,0xE6,0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,
+0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,
+0x84,0xC4,0x74,0x08,0x33,0xF6,0xE8,0x53,0xFE,0xEB,0xEE,0x90,0xB8,0x00,0x80,0xBA,
+0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,
+0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x02,0x00,0xE8,0x2C,0xFE,
+0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,
+0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,
+0xBE,0x04,0x00,0xE8,0x06,0xFE,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,
+0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x62,0x12,0xE6,0xFE,
+0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x06,0x00,0xE8,0xE0,0xFD,0xEB,0xED,0xB8,0x00,
 0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
-0xD8,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8,
-0x06,0xFE,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,
-0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,
-0x74,0x08,0xBE,0x06,0x00,0xE8,0xE0,0xFD,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,
-0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,
-0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x37,0xFE,0xA1,0x60,0x12,
-0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0xAA,0xFD,0xEB,0xDD,
-0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5C,0x12,0xE6,0xFE,
-0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,
-0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,
-0x74,0x19,0xBE,0x04,0x00,0xE8,0xEC,0xFD,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,
-0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x5F,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,
-0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x04,0x07,0xE4,0x04,
-0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
-0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x27,
-0xFD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,
-0x92,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,
+0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x37,
+0xFE,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,
+0xAA,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,
+0x5C,0x12,0xE6,0xFE,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,
+0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,
+0xE4,0x00,0x22,0xC4,0x74,0x19,0xBE,0x04,0x00,0xE8,0xEC,0xFD,0xA1,0x62,0x12,0xE6,
+0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x5F,0xFD,0xEB,0xDC,0xA1,
+0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,
 0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,
-0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x19,
-0xBE,0x02,0x00,0xE8,0xE2,0xFC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,
-0xE4,0xBE,0x0C,0x00,0xE8,0x4D,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,
-0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,
-0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,
-0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x9D,0xFC,0xA1,0x60,0x12,0xE6,0xFE,
-0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0x8C,0xFC,0xEB,0xDD,0xA1,0x60,
-0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA,0x22,
-0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,
-0xE4,0x80,0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0x5C,0xFC,0xA1,0x62,0x12,0xE6,
-0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x4B,0xFC,0xEB,0xDC,0xA1,
-0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA,
-0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0x2A,0xC0,
-0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0x14,0x33,0xDB,0xE8,0xD5,0xF6,0xEB,0xEF,0x90,
-0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xF6,0x06,0x05,0x01,
-0x01,0x75,0xED,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0xE3,0xBB,0x04,0x00,
-0xE8,0xAF,0xF6,0xEB,0xC9,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0xFB,0x90,
-0xFA,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x13,0x33,0xDB,0xE8,0xCC,0xF8,
-0xEB,0xEC,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xA8,0x04,
-0x74,0xF0,0x33,0xDB,0xE8,0x5B,0xF7,0xEB,0xD5,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
-0xD8,0x90,0xFB,0x90,0xFA,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x15,0xBB,
-0x04,0x00,0xE8,0x97,0xF8,0xEB,0xEB,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,
-0x1F,0x61,0xCF,0x90,0xA8,0x04,0x74,0xF0,0xBB,0x04,0x00,0xE8,0x24,0xF7,0xEB,0xD2,
-0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x09,0x9C,0x0E,0xE8,0x6B,0xF2,0x90,0x6A,0x00,
-0x1F,0xC6,0x06,0x93,0x12,0x29,0x9C,0x0E,0xE8,0x5D,0xF2,0x90,0x6E,0x20,0x6E,0x20,
-0x6E,0x20,0xCA,0x1D,0x8E,0x1C,0xE2,0x1C,0x16,0x1E,0x6E,0x20,0x7E,0x1D,0xAA,0x1E,
-0x34,0x1F,0x6E,0x20,0x7E,0x1D,0x6E,0x20,0x6E,0x20,0x34,0x1F,0x6E,0x20,0x6E,0x20,
-0x6E,0x20,0xF0,0x1D,0xB8,0x1C,0x30,0x1D,0x60,0x1E,0x6E,0x20,0xA4,0x1D,0xEE,0x1E,
-0x74,0x1F,0x6E,0x20,0xA4,0x1D,0x6E,0x20,0x6E,0x20,0x74,0x1F,0xFC,0xB9,0x40,0x00,
-0x8C,0xCB,0xB8,0x60,0x20,0x2B,0xFF,0xAB,0x93,0xAB,0x93,0xE2,0xFA,0xC7,0x06,0x4C,
-0x00,0xA4,0x11,0x83,0x3E,0x44,0x12,0x00,0x75,0x20,0xC7,0x06,0x3C,0x00,0xEA,0x4A,
-0xC7,0x06,0x30,0x00,0xB6,0x1F,0xC7,0x06,0x34,0x00,0xF6,0x1F,0xF6,0x06,0x05,0x01,
-0x01,0x75,0x06,0xC7,0x06,0x38,0x00,0x2A,0x20,0xC3,0xC7,0x06,0x3C,0x00,0x38,0x4B,
-0x33,0xDB,0x8A,0x1E,0x54,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x56,0x12,0x2E,0x8B,0x87,
-0x7C,0x20,0xA3,0x30,0x00,0x8A,0x1E,0x55,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x57,0x12,
-0x2E,0x8B,0x87,0x9C,0x20,0xA3,0x34,0x00,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x86,
-0xC4,0xE6,0xD0,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x33,0xD2,0x8A,0xD4,0xC3,0x51,
-0xB9,0x10,0x27,0xE4,0x0A,0x90,0x90,0x84,0xC0,0x74,0x05,0xE2,0xF6,0x59,0xF9,0xC3,
-0x59,0xF8,0xC3,0x84,0xC0,0x78,0x1E,0x51,0x8A,0xE8,0x8A,0xC8,0xB8,0x01,0x00,0xD3,
-0xE0,0x09,0x86,0x98,0x00,0x3A,0xAE,0xA0,0x00,0x59,0x75,0x10,0xE8,0xA9,0xE5,0x83,
-0x4E,0x26,0x02,0xF9,0xC3,0x98,0x89,0x86,0x98,0x00,0xEB,0xF0,0xF8,0xC3,0x84,0xC0,
-0x78,0x12,0x51,0x8A,0xE0,0x8A,0xC8,0xB8,0x01,0x00,0xD3,0xE0,0x59,0xF7,0xD0,0x21,
-0x86,0x98,0x00,0xC3,0xC7,0x86,0x98,0x00,0x00,0x00,0xC3,0x83,0xC2,0x04,0x8A,0x86,
-0xA6,0x00,0x0C,0x04,0xEE,0x83,0xEA,0x04,0xC3,0xE8,0x93,0xFF,0x72,0x04,0xB0,0x82,
-0xE6,0x0A,0xC3,0x8B,0x46,0x26,0xA8,0xFD,0x74,0x11,0x8A,0x86,0xA5,0x00,0xA8,0x06,
-0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC4,0x01,0x74,0x0A,
-0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xEB,0x0C,0xA8,0x02,0x75,0x0F,0x8A,0x86,
-0xA5,0x00,0x24,0xFD,0x0C,0x04,0x3A,0x86,0xA5,0x00,0x75,0xD8,0xC3,0x8A,0x86,0xA5,
-0x00,0xEB,0xCF,0xE4,0xD8,0x33,0xDB,0x8A,0xD8,0xC0,0xEB,0x04,0x2E,0x8A,0x9F,0x62,
-0x17,0x88,0x9E,0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,
-0xA8,0x10,0x75,0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x80,0x75,0x03,
-0x80,0xCB,0x40,0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0xFD,0x74,0x0D,0xA8,
-0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC7,0x01,0x74,
-0x04,0x0C,0x02,0xEB,0xF0,0xF6,0xC3,0x02,0x75,0xE9,0x0C,0x04,0xEB,0xE7,0xC4,0x04,
-0xC4,0x04,0x85,0x04,0x59,0x04,0x48,0x04,0x41,0x04,0xC3,0x03,0x82,0x03,0x41,0x03,
-0x82,0x02,0x57,0x02,0x41,0x02,0x82,0x01,0x41,0x01,0x82,0x00,0x41,0x00,0x4E,0x02,
-0xAD,0x01,0x57,0x01,0x2D,0x00,0x2B,0x00,0x27,0x00,0x21,0x00,0x16,0x00,0xF4,0x04,
-0xF4,0x04,0xA3,0x04,0x6F,0x04,0x5B,0x04,0x51,0x04,0xF4,0x03,0xA3,0x03,0x51,0x03,
-0xA3,0x02,0x6D,0x02,0x51,0x02,0xA3,0x01,0x51,0x01,0xA3,0x00,0x51,0x00,0x62,0x02,
-0xD9,0x01,0x6D,0x01,0x38,0x00,0x36,0x00,0x31,0x00,0x29,0x00,0x1B,0x00,0x51,0x57,
-0xBF,0x02,0x00,0xEB,0x0F,0x90,0x51,0x56,0xBF,0x01,0x00,0xEB,0x07,0x90,0x51,0x56,
-0xBF,0x03,0x00,0x90,0x3C,0x19,0x76,0x02,0xB0,0x17,0x98,0x8B,0xF0,0x8A,0x82,0xC4,
-0x00,0x2A,0xE4,0x8B,0xF0,0x83,0xFE,0x18,0x73,0x46,0xD1,0xE6,0x2E,0x8B,0x8C,0x4E,
-0x22,0xF7,0x46,0x38,0x80,0x00,0x74,0x05,0x2E,0x8B,0x8C,0x7E,0x22,0xF7,0xC7,0x02,
-0x00,0x74,0x12,0x3B,0x8E,0x94,0x00,0x74,0x0C,0x89,0x8E,0x94,0x00,0x8A,0xC5,0xE6,
-0xEC,0x8A,0xC1,0xE6,0xE4,0xF7,0xC7,0x01,0x00,0x74,0x12,0x3B,0x8E,0x96,0x00,0x74,
-0x0C,0x89,0x8E,0x96,0x00,0x8A,0xC5,0xE6,0xF8,0x8A,0xC1,0xE6,0xF0,0x5E,0x59,0xC3,
-0x77,0x06,0x8B,0x8E,0x8E,0x00,0xEB,0xC5,0x8B,0x8E,0x90,0x00,0xEB,0xBF,0xD5,0x03,
-0xF6,0x00,0x3E,0x00,0x10,0x00,0x04,0x00,0xCA,0x04,0x33,0x01,0x4D,0x00,0x14,0x00,
-0x05,0x00,0x01,0x03,0x05,0x07,0x09,0x00,0x01,0x02,0x03,0x04,0x80,0x84,0x1E,0x00,
-0xA0,0x25,0x26,0x00,0x00,0x00,0x60,0x8B,0xF0,0x33,0xFF,0x2E,0xA1,0x4C,0x23,0x2E,
-0x8B,0x16,0x4E,0x23,0xBB,0x2E,0x23,0xF7,0x46,0x38,0x80,0x00,0x74,0x0C,0x2E,0xA1,
-0x50,0x23,0x2E,0x8B,0x16,0x52,0x23,0xBB,0x38,0x23,0xB9,0x05,0x00,0x2E,0x3B,0x31,
-0x73,0x0A,0x47,0x47,0xE2,0xF7,0xB8,0xFF,0xFF,0xEB,0x1D,0x90,0xD1,0xEF,0x2E,0x8A,
-0x8D,0x42,0x23,0x2A,0xED,0xD1,0xEA,0xD1,0xD8,0xE2,0xFA,0xF7,0xF6,0x05,0x02,0x00,
-0xC1,0xE8,0x02,0x2E,0x8A,0xA5,0x47,0x23,0x2E,0xA3,0x54,0x23,0x61,0x2E,0xA1,0x54,
-0x23,0xC3,0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x60,0x09,0x08,0x00,0x20,0x00,
-0x80,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,
-0x52,0x56,0x57,0x85,0xC0,0x74,0x05,0x3D,0x01,0x09,0x76,0x03,0xB8,0x01,0x09,0xBF,
-0x5B,0x01,0xF7,0x46,0x38,0x80,0x00,0x74,0x03,0xBF,0xB2,0x01,0x33,0xF6,0x2E,0x3B,
-0x84,0xB2,0x23,0x76,0x04,0x46,0x46,0xEB,0xF5,0xF7,0xE7,0x2E,0x8B,0xBC,0xBC,0x23,
-0x03,0xC7,0x83,0xD2,0x00,0xD1,0xE7,0xF7,0xF7,0x2E,0x8A,0xA4,0xC6,0x23,0x5F,0x5E,
-0x5A,0xC3,0xE4,0x3E,0x80,0xBE,0xC3,0x00,0x03,0x75,0x0C,0xF7,0x46,0x7A,0x20,0x00,
-0x74,0x05,0x0C,0x80,0xE6,0x3E,0xC3,0x24,0x7F,0xE6,0x3E,0xC3,0x24,0x03,0x88,0x86,
-0xC3,0x00,0x8A,0xE0,0xE4,0x10,0x24,0xFC,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,
-0x42,0xE8,0xCE,0xFF,0xC3,0x90,0x56,0x8B,0xF0,0x83,0xE6,0x07,0xD1,0xE6,0x2E,0xFF,
-0xA4,0x54,0x24,0x90,0x64,0x24,0x68,0x24,0x6C,0x24,0x70,0x24,0x74,0x24,0x83,0x24,
-0x83,0x24,0x83,0x24,0xB4,0x00,0xEB,0x0E,0xB4,0xC0,0xEB,0x0A,0xB4,0x40,0xEB,0x06,
-0xB4,0x20,0xEB,0x02,0xB4,0xA0,0xE4,0x10,0x24,0x1F,0x0A,0xC4,0xE6,0x10,0x80,0x8E,
-0xA1,0x00,0x42,0x5E,0xC3,0x90,0x3C,0x02,0x77,0x12,0x8A,0xE0,0xE4,0x10,0x24,0xF3,
-0xC0,0xE4,0x02,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xC3,0x90,0x8B,0x5E,
-0x38,0x84,0xC0,0x74,0x1F,0x3C,0x02,0x74,0x20,0x83,0xCB,0x08,0x8B,0x46,0x2E,0x3B,
-0x46,0x3C,0x77,0x0C,0xE8,0x88,0xFC,0x72,0x07,0xB0,0x24,0xE6,0x0A,0x83,0xCB,0x10,
-0x89,0x5E,0x38,0xC3,0x83,0xE3,0xF7,0xEB,0xF7,0xF7,0xC3,0x10,0x00,0x74,0xF5,0xE8,
-0x6D,0xFC,0x72,0xEC,0x8A,0x86,0xC0,0x00,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xEB,0xE0,
-0x8B,0x5E,0x38,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0xE4,0xD8,0x77,0x0B,0x24,0xFE,0x80,
-0xCB,0x12,0xE6,0xD8,0x89,0x5E,0x38,0xC3,0x0C,0x01,0x80,0xCB,0x02,0xEB,0xF3,0x50,
-0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A,
-0xDC,0x2E,0x8A,0xA7,0x62,0x17,0x09,0x46,0x3E,0x58,0xC3,0x50,0x33,0xDB,0xC1,0xE8,
-0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A,0xDC,0x2E,0x8A,0xA7,
-0x62,0x17,0xF7,0xD0,0x21,0x46,0x3E,0x58,0xC3,0x8B,0x46,0x3E,0x33,0xDB,0x8A,0xD8,
-0x0A,0xDC,0x2E,0x8A,0x87,0x72,0x17,0xE6,0x2C,0x8A,0xE0,0xE4,0x2A,0x24,0x0F,0x0A,
-0xC4,0xE6,0x2A,0x8A,0x86,0xA5,0x00,0x84,0xE4,0x75,0x0D,0xA8,0x80,0x74,0x11,0x24,
-0x7F,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x80,0x75,0x04,0x0C,0x80,0xEB,0xF1,
-0xC3,0x1E,0x60,0x33,0xC9,0x33,0xD2,0x33,0xF6,0x8E,0xD9,0x8D,0xBE,0xFD,0x00,0x57,
-0x8B,0x05,0x84,0xC0,0x74,0x16,0x8B,0xD1,0x42,0x8B,0xFE,0x4F,0x78,0x09,0x38,0xA3,
-0xE4,0x00,0x74,0x08,0x4F,0x79,0xF7,0x88,0xA2,0xE4,0x00,0x46,0x5F,0x83,0xC7,0x09,
-0x41,0x83,0xF9,0x10,0x72,0xD9,0x89,0xB6,0x86,0x00,0x89,0x96,0x84,0x00,0x61,0x1F,
-0xC3,0x53,0xC7,0x46,0x66,0x00,0x00,0x8B,0x46,0x64,0xA9,0x40,0x00,0x74,0x0D,0xB3,
-0x00,0xA9,0x80,0x00,0x74,0x02,0xB3,0x7F,0x88,0x9E,0xC1,0x00,0x32,0xDB,0xA9,0x02,
-0x00,0x74,0x03,0x80,0xCB,0x40,0xA9,0x00,0x40,0x74,0x03,0x80,0xCB,0x02,0xA9,0x00,
-0x80,0x74,0x03,0x80,0xCB,0x01,0xA9,0x30,0x1E,0x74,0x03,0x80,0xCB,0xBC,0xA9,0x00,
-0x20,0x74,0x03,0x80,0xCB,0x08,0xA9,0x04,0x01,0x74,0x03,0x80,0xCB,0x10,0xA9,0x08,
-0x00,0x74,0x03,0x80,0xCB,0x20,0x88,0x9E,0xC2,0x00,0x5B,0xC3,0x06,0x51,0x57,0x50,
-0x16,0x07,0x8D,0xBE,0xC4,0x00,0xB9,0x1F,0x00,0x33,0xC0,0xAA,0x40,0xE2,0xFC,0x8B,
-0x86,0x92,0x00,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x58,0x5F,0x59,0x07,0xC3,
-0xE4,0xD8,0xC0,0xE8,0x04,0x53,0x25,0x0F,0x00,0x8B,0xD8,0x2E,0x8A,0x87,0x62,0x17,
-0x88,0x86,0xA9,0x00,0x5A,0xC3,0x08,0x86,0xAC,0x00,0xC6,0x86,0xBA,0x00,0x01,0xB0,
-0x0E,0xE8,0xEA,0xE9,0xC3,0xAD,0x36,0xA3,0xB4,0x13,0xAD,0x36,0xA3,0xB6,0x13,0xAD,
-0x36,0xA3,0xB8,0x13,0x83,0xE9,0x06,0x36,0xF7,0x06,0xB6,0x13,0x0F,0x00,0xC3,0x8A,
-0x46,0x26,0xF7,0x46,0x48,0x80,0x00,0x74,0x02,0x0C,0x10,0x88,0x86,0xBD,0x00,0x32,
-0xC0,0x83,0x7E,0x1A,0x00,0x75,0x0E,0x8B,0x5E,0x40,0x43,0x80,0xE3,0xFE,0x3B,0x5E,
-0x08,0x75,0x02,0x0C,0x01,0x83,0x7E,0x3A,0x00,0x75,0x0D,0x1E,0xC5,0x5E,0x14,0x8B,
-0x1F,0x1F,0x85,0xDB,0x75,0x02,0x0C,0x02,0xF7,0x46,0x38,0x10,0x00,0x74,0x02,0x0C,
-0x04,0xF7,0x46,0x7A,0x02,0x00,0x74,0x02,0x0C,0x08,0x88,0x86,0xBF,0x00,0xC3,0x90,
-0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x0D,0x9C,0x0E,0xE8,0x0B,0xEC,0x90,0xB0,0x02,
-0xE6,0xDA,0xF8,0xC3,0x33,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x01,0xE6,0xD8,0xF8,0xC3,
-0x33,0xC0,0xE6,0xD8,0xF8,0xC3,0xB0,0xFF,0xE8,0x68,0xFA,0xE8,0xBB,0xFA,0xF8,0xC3,
-0xAC,0x49,0xE8,0xC9,0xFB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x2F,0xFD,0xF8,0xC3,0x90,
-0xAC,0x49,0xE8,0x81,0xFD,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x39,0xFD,0xF8,0xC3,0x90,
-0xAC,0x49,0xE6,0x34,0xF8,0xC3,0xAC,0x49,0xE6,0x36,0xF8,0xC3,0xAC,0x49,0x3C,0x02,
-0x77,0x1F,0x84,0xC0,0x75,0x1D,0xE4,0x14,0x24,0xEF,0xE6,0x14,0xE4,0x12,0x24,0x3F,
-0xE6,0x12,0xE4,0x16,0xA8,0x04,0x74,0x09,0xE8,0x04,0xFA,0x72,0x04,0xB0,0x18,0xE6,
-0x0A,0xF8,0xC3,0x8A,0xE0,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,0x12,0x0C,0xC0,0xF6,
-0xC4,0x01,0x74,0x02,0x24,0x7F,0xE6,0x12,0xF8,0xC3,0xAC,0x49,0xE8,0x3F,0xFD,0xF8,
-0xC3,0x90,0xB8,0x00,0x40,0xE8,0x97,0xFD,0xE8,0xCE,0xFD,0xE8,0xC2,0xFE,0xB0,0x01,
-0xE8,0xD3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x9F,0xFD,0xE8,0xBA,0xFD,0xF8,
-0xC3,0x90,0xB8,0x00,0x10,0xE8,0x77,0xFD,0xE8,0xAE,0xFD,0xE8,0xA2,0xFE,0xB0,0x08,
-0xE8,0xB3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x7F,0xFD,0xE8,0x9A,0xFD,0xF8,
-0xC3,0x90,0xB8,0x00,0x80,0xE8,0x57,0xFD,0xE8,0x8E,0xFD,0xE8,0x82,0xFE,0xB0,0x02,
-0xE8,0x93,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x5F,0xFD,0xE8,0x7A,0xFD,0xF8,
-0xC3,0x90,0xB8,0x00,0x20,0xE8,0x37,0xFD,0xE8,0x6E,0xFD,0xE8,0x62,0xFE,0xB0,0x04,
-0xE8,0x73,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x3F,0xFD,0xE8,0x5A,0xFD,0xF8,
-0xC3,0x90,0xAC,0x49,0xE8,0x48,0x14,0xE4,0x3C,0x24,0xE7,0x0A,0xC4,0xE6,0x3C,0xF8,
-0xC3,0x90,0xB8,0xDE,0x3B,0x89,0x46,0x7C,0xE4,0x3C,0x0C,0x18,0xE6,0x3C,0xF8,0xC3,
-0xE4,0x12,0x0C,0x02,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFD,0xEB,0xF6,0xE8,0xCF,
-0xFC,0xF8,0xC3,0x90,0x83,0x66,0x38,0xFD,0xF8,0xC3,0xAC,0x49,0xA8,0x01,0x74,0x06,
-0x83,0x4E,0x7A,0x20,0xEB,0x04,0x83,0x66,0x7A,0xDF,0xE8,0xE5,0xFB,0xF8,0xC3,0x90,
+0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18,
+0x33,0xF6,0xE8,0x27,0xFD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5,
+0xBE,0x08,0x00,0xE8,0x92,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,
+0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,
+0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x80,
+0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0xE2,0xFC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,
+0x00,0x22,0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x4D,0xFD,0xEB,0xDC,0xA1,0x62,0x12,
+0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,
+0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,
+0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x9D,0xFC,0xA1,
+0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0x8C,0xFC,
+0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,
+0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,
+0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0x5C,0xFC,
+0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x4B,
+0xFC,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,
+0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
+0xD8,0x90,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0x14,0x33,0xDB,0xE8,0xD5,
+0xF6,0xEB,0xEF,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,
+0xF6,0x06,0x05,0x01,0x01,0x75,0xED,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,
+0xE3,0xBB,0x04,0x00,0xE8,0xAF,0xF6,0xEB,0xC9,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,
+0xD8,0x90,0xFB,0x90,0xFA,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x13,0x33,
+0xDB,0xE8,0xCC,0xF8,0xEB,0xEC,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,
+0xCF,0x90,0xA8,0x04,0x74,0xF0,0x33,0xDB,0xE8,0x5B,0xF7,0xEB,0xD5,0x90,0x60,0x1E,
+0x06,0x2B,0xC0,0x8E,0xD8,0x90,0xFB,0x90,0xFA,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,
+0x02,0x74,0x15,0xBB,0x04,0x00,0xE8,0x97,0xF8,0xEB,0xEB,0x90,0xB8,0x00,0x80,0xBA,
+0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xA8,0x04,0x74,0xF0,0xBB,0x04,0x00,0xE8,
+0x24,0xF7,0xEB,0xD2,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x09,0x9C,0x0E,0xE8,0x6B,
+0xF2,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x29,0x9C,0x0E,0xE8,0x5D,0xF2,0x90,
+0x72,0x20,0x72,0x20,0x72,0x20,0xCE,0x1D,0x92,0x1C,0xE6,0x1C,0x1A,0x1E,0x72,0x20,
+0x82,0x1D,0xAE,0x1E,0x38,0x1F,0x72,0x20,0x82,0x1D,0x72,0x20,0x72,0x20,0x38,0x1F,
+0x72,0x20,0x72,0x20,0x72,0x20,0xF4,0x1D,0xBC,0x1C,0x34,0x1D,0x64,0x1E,0x72,0x20,
+0xA8,0x1D,0xF2,0x1E,0x78,0x1F,0x72,0x20,0xA8,0x1D,0x72,0x20,0x72,0x20,0x78,0x1F,
+0xFC,0xB9,0x40,0x00,0x8C,0xCB,0xB8,0x64,0x20,0x2B,0xFF,0xAB,0x93,0xAB,0x93,0xE2,
+0xFA,0xC7,0x06,0x4C,0x00,0xA8,0x11,0x83,0x3E,0x44,0x12,0x00,0x75,0x20,0xC7,0x06,
+0x3C,0x00,0x08,0x4B,0xC7,0x06,0x30,0x00,0xBA,0x1F,0xC7,0x06,0x34,0x00,0xFA,0x1F,
+0xF6,0x06,0x05,0x01,0x01,0x75,0x06,0xC7,0x06,0x38,0x00,0x2E,0x20,0xC3,0xC7,0x06,
+0x3C,0x00,0x56,0x4B,0x33,0xDB,0x8A,0x1E,0x54,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x56,
+0x12,0x2E,0x8B,0x87,0x80,0x20,0xA3,0x30,0x00,0x8A,0x1E,0x55,0x12,0xC1,0xE3,0x02,
+0x02,0x1E,0x57,0x12,0x2E,0x8B,0x87,0xA0,0x20,0xA3,0x34,0x00,0xC3,0x8B,0x86,0x9E,
+0x00,0xE6,0xFE,0x86,0xC4,0xE6,0xD0,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x33,0xD2,
+0x8A,0xD4,0xC3,0x51,0xB9,0x10,0x27,0xE4,0x0A,0x90,0x90,0x84,0xC0,0x74,0x05,0xE2,
+0xF6,0x59,0xF9,0xC3,0x59,0xF8,0xC3,0x84,0xC0,0x78,0x1E,0x51,0x8A,0xE8,0x8A,0xC8,
+0xB8,0x01,0x00,0xD3,0xE0,0x09,0x86,0x98,0x00,0x3A,0xAE,0xA0,0x00,0x59,0x75,0x10,
+0xE8,0xA9,0xE5,0x83,0x4E,0x26,0x02,0xF9,0xC3,0x98,0x89,0x86,0x98,0x00,0xEB,0xF0,
+0xF8,0xC3,0x84,0xC0,0x78,0x12,0x51,0x8A,0xE0,0x8A,0xC8,0xB8,0x01,0x00,0xD3,0xE0,
+0x59,0xF7,0xD0,0x21,0x86,0x98,0x00,0xC3,0xC7,0x86,0x98,0x00,0x00,0x00,0xC3,0x83,
+0xC2,0x04,0x8A,0x86,0xA6,0x00,0x0C,0x04,0xEE,0x83,0xEA,0x04,0xC3,0xE8,0x93,0xFF,
+0x72,0x04,0xB0,0x82,0xE6,0x0A,0xC3,0x8B,0x46,0x26,0xA8,0xFD,0x74,0x11,0x8A,0x86,
+0xA5,0x00,0xA8,0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,
+0xC4,0x01,0x74,0x0A,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xEB,0x0C,0xA8,0x02,
+0x75,0x0F,0x8A,0x86,0xA5,0x00,0x24,0xFD,0x0C,0x04,0x3A,0x86,0xA5,0x00,0x75,0xD8,
+0xC3,0x8A,0x86,0xA5,0x00,0xEB,0xCF,0xE4,0xD8,0x33,0xDB,0x8A,0xD8,0xC0,0xEB,0x04,
+0x2E,0x8A,0x9F,0x66,0x17,0x88,0x9E,0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,
+0xC7,0x04,0x74,0x07,0xA8,0x10,0x75,0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,
+0xA8,0x80,0x75,0x03,0x80,0xCB,0x40,0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0xF6,0xC3,
+0xFD,0x74,0x0D,0xA8,0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,
+0xF6,0xC7,0x01,0x74,0x04,0x0C,0x02,0xEB,0xF0,0xF6,0xC3,0x02,0x75,0xE9,0x0C,0x04,
+0xEB,0xE7,0xC4,0x04,0xC4,0x04,0x85,0x04,0x59,0x04,0x48,0x04,0x41,0x04,0xC3,0x03,
+0x82,0x03,0x41,0x03,0x82,0x02,0x57,0x02,0x41,0x02,0x82,0x01,0x41,0x01,0x82,0x00,
+0x41,0x00,0x4E,0x02,0xAD,0x01,0x57,0x01,0x2D,0x00,0x2B,0x00,0x27,0x00,0x21,0x00,
+0x16,0x00,0xF4,0x04,0xF4,0x04,0xA3,0x04,0x6F,0x04,0x5B,0x04,0x51,0x04,0xF4,0x03,
+0xA3,0x03,0x51,0x03,0xA3,0x02,0x6D,0x02,0x51,0x02,0xA3,0x01,0x51,0x01,0xA3,0x00,
+0x51,0x00,0x62,0x02,0xD9,0x01,0x6D,0x01,0x38,0x00,0x36,0x00,0x31,0x00,0x29,0x00,
+0x1B,0x00,0x51,0x57,0xBF,0x02,0x00,0xEB,0x0F,0x90,0x51,0x56,0xBF,0x01,0x00,0xEB,
+0x07,0x90,0x51,0x56,0xBF,0x03,0x00,0x90,0x3C,0x19,0x76,0x02,0xB0,0x17,0x98,0x8B,
+0xF0,0x8A,0x82,0xC4,0x00,0x2A,0xE4,0x8B,0xF0,0x83,0xFE,0x18,0x73,0x46,0xD1,0xE6,
+0x2E,0x8B,0x8C,0x52,0x22,0xF7,0x46,0x38,0x80,0x00,0x74,0x05,0x2E,0x8B,0x8C,0x82,
+0x22,0xF7,0xC7,0x02,0x00,0x74,0x12,0x3B,0x8E,0x94,0x00,0x74,0x0C,0x89,0x8E,0x94,
+0x00,0x8A,0xC5,0xE6,0xEC,0x8A,0xC1,0xE6,0xE4,0xF7,0xC7,0x01,0x00,0x74,0x12,0x3B,
+0x8E,0x96,0x00,0x74,0x0C,0x89,0x8E,0x96,0x00,0x8A,0xC5,0xE6,0xF8,0x8A,0xC1,0xE6,
+0xF0,0x5E,0x59,0xC3,0x77,0x06,0x8B,0x8E,0x8E,0x00,0xEB,0xC5,0x8B,0x8E,0x90,0x00,
+0xEB,0xBF,0xD5,0x03,0xF6,0x00,0x3E,0x00,0x10,0x00,0x04,0x00,0xCA,0x04,0x33,0x01,
+0x4D,0x00,0x14,0x00,0x05,0x00,0x01,0x03,0x05,0x07,0x09,0x00,0x01,0x02,0x03,0x04,
+0x80,0x84,0x1E,0x00,0xA0,0x25,0x26,0x00,0x00,0x00,0x60,0x8B,0xF0,0x33,0xFF,0x2E,
+0xA1,0x50,0x23,0x2E,0x8B,0x16,0x52,0x23,0xBB,0x32,0x23,0xF7,0x46,0x38,0x80,0x00,
+0x74,0x0C,0x2E,0xA1,0x54,0x23,0x2E,0x8B,0x16,0x56,0x23,0xBB,0x3C,0x23,0xB9,0x05,
+0x00,0x2E,0x3B,0x31,0x73,0x0A,0x47,0x47,0xE2,0xF7,0xB8,0xFF,0xFF,0xEB,0x1D,0x90,
+0xD1,0xEF,0x2E,0x8A,0x8D,0x46,0x23,0x2A,0xED,0xD1,0xEA,0xD1,0xD8,0xE2,0xFA,0xF7,
+0xF6,0x05,0x02,0x00,0xC1,0xE8,0x02,0x2E,0x8A,0xA5,0x4B,0x23,0x2E,0xA3,0x58,0x23,
+0x61,0x2E,0xA1,0x58,0x23,0xC3,0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x60,0x09,
+0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x01,0x00,0x02,0x00,
+0x03,0x00,0x04,0x00,0x52,0x56,0x57,0x85,0xC0,0x74,0x05,0x3D,0x01,0x09,0x76,0x03,
+0xB8,0x01,0x09,0xBF,0x5B,0x01,0xF7,0x46,0x38,0x80,0x00,0x74,0x03,0xBF,0xB2,0x01,
+0x33,0xF6,0x2E,0x3B,0x84,0xB6,0x23,0x76,0x04,0x46,0x46,0xEB,0xF5,0xF7,0xE7,0x2E,
+0x8B,0xBC,0xC0,0x23,0x03,0xC7,0x83,0xD2,0x00,0xD1,0xE7,0xF7,0xF7,0x2E,0x8A,0xA4,
+0xCA,0x23,0x5F,0x5E,0x5A,0xC3,0xE4,0x3E,0x80,0xBE,0xC3,0x00,0x03,0x75,0x0C,0xF7,
+0x46,0x7A,0x20,0x00,0x74,0x05,0x0C,0x80,0xE6,0x3E,0xC3,0x24,0x7F,0xE6,0x3E,0xC3,
+0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xE0,0xE4,0x10,0x24,0xFC,0x0A,0xC4,0xE6,0x10,
+0x80,0x8E,0xA1,0x00,0x42,0xE8,0xCE,0xFF,0xC3,0x90,0x56,0x8B,0xF0,0x83,0xE6,0x07,
+0xD1,0xE6,0x2E,0xFF,0xA4,0x58,0x24,0x90,0x68,0x24,0x6C,0x24,0x70,0x24,0x74,0x24,
+0x78,0x24,0x87,0x24,0x87,0x24,0x87,0x24,0xB4,0x00,0xEB,0x0E,0xB4,0xC0,0xEB,0x0A,
+0xB4,0x40,0xEB,0x06,0xB4,0x20,0xEB,0x02,0xB4,0xA0,0xE4,0x10,0x24,0x1F,0x0A,0xC4,
+0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0x5E,0xC3,0x90,0x3C,0x02,0x77,0x12,0x8A,0xE0,
+0xE4,0x10,0x24,0xF3,0xC0,0xE4,0x02,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,
+0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x1F,0x3C,0x02,0x74,0x20,0x83,0xCB,0x08,
+0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x77,0x0C,0xE8,0x88,0xFC,0x72,0x07,0xB0,0x24,0xE6,
+0x0A,0x83,0xCB,0x10,0x89,0x5E,0x38,0xC3,0x83,0xE3,0xF7,0xEB,0xF7,0xF7,0xC3,0x10,
+0x00,0x74,0xF5,0xE8,0x6D,0xFC,0x72,0xEC,0x8A,0x86,0xC0,0x00,0xE6,0x38,0xB0,0x23,
+0xE6,0x0A,0xEB,0xE0,0x8B,0x5E,0x38,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0xE4,0xD8,0x77,
+0x0B,0x24,0xFE,0x80,0xCB,0x12,0xE6,0xD8,0x89,0x5E,0x38,0xC3,0x0C,0x01,0x80,0xCB,
+0x02,0xEB,0xF3,0x50,0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,
+0x87,0x66,0x17,0x8A,0xDC,0x2E,0x8A,0xA7,0x66,0x17,0x09,0x46,0x3E,0x58,0xC3,0x50,
+0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x66,0x17,0x8A,
+0xDC,0x2E,0x8A,0xA7,0x66,0x17,0xF7,0xD0,0x21,0x46,0x3E,0x58,0xC3,0x8B,0x46,0x3E,
+0x33,0xDB,0x8A,0xD8,0x0A,0xDC,0x2E,0x8A,0x87,0x76,0x17,0xE6,0x2C,0x8A,0xE0,0xE4,
+0x2A,0x24,0x0F,0x0A,0xC4,0xE6,0x2A,0x8A,0x86,0xA5,0x00,0x84,0xE4,0x75,0x0D,0xA8,
+0x80,0x74,0x11,0x24,0x7F,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x80,0x75,0x04,
+0x0C,0x80,0xEB,0xF1,0xC3,0x1E,0x60,0x33,0xC9,0x33,0xD2,0x33,0xF6,0x8E,0xD9,0x8D,
+0xBE,0xFD,0x00,0x57,0x8B,0x05,0x84,0xC0,0x74,0x16,0x8B,0xD1,0x42,0x8B,0xFE,0x4F,
+0x78,0x09,0x38,0xA3,0xE4,0x00,0x74,0x08,0x4F,0x79,0xF7,0x88,0xA2,0xE4,0x00,0x46,
+0x5F,0x83,0xC7,0x09,0x41,0x83,0xF9,0x10,0x72,0xD9,0x89,0xB6,0x86,0x00,0x89,0x96,
+0x84,0x00,0x61,0x1F,0xC3,0x53,0xC7,0x46,0x66,0x00,0x00,0x8B,0x46,0x64,0xA9,0x40,
+0x00,0x74,0x0D,0xB3,0x00,0xA9,0x80,0x00,0x74,0x02,0xB3,0x7F,0x88,0x9E,0xC1,0x00,
+0x32,0xDB,0xA9,0x02,0x00,0x74,0x03,0x80,0xCB,0x40,0xA9,0x00,0x40,0x74,0x03,0x80,
+0xCB,0x02,0xA9,0x00,0x80,0x74,0x03,0x80,0xCB,0x01,0xA9,0x30,0x1E,0x74,0x03,0x80,
+0xCB,0xBC,0xA9,0x00,0x20,0x74,0x03,0x80,0xCB,0x08,0xA9,0x04,0x01,0x74,0x03,0x80,
+0xCB,0x10,0xA9,0x08,0x00,0x74,0x03,0x80,0xCB,0x20,0x88,0x9E,0xC2,0x00,0x5B,0xC3,
+0x06,0x51,0x57,0x50,0x16,0x07,0x8D,0xBE,0xC4,0x00,0xB9,0x1F,0x00,0x33,0xC0,0xAA,
+0x40,0xE2,0xFC,0x8B,0x86,0x92,0x00,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x58,
+0x5F,0x59,0x07,0xC3,0xE4,0xD8,0xC0,0xE8,0x04,0x53,0x25,0x0F,0x00,0x8B,0xD8,0x2E,
+0x8A,0x87,0x66,0x17,0x88,0x86,0xA9,0x00,0x5A,0xC3,0x08,0x86,0xAC,0x00,0xC6,0x86,
+0xBA,0x00,0x01,0xB0,0x0E,0xE8,0xEA,0xE9,0xC3,0xAD,0x36,0xA3,0xB4,0x13,0xAD,0x36,
+0xA3,0xB6,0x13,0xAD,0x36,0xA3,0xB8,0x13,0x83,0xE9,0x06,0x36,0xF7,0x06,0xB6,0x13,
+0x0F,0x00,0xC3,0x8A,0x46,0x26,0xF7,0x46,0x48,0x80,0x00,0x74,0x02,0x0C,0x10,0x88,
+0x86,0xBD,0x00,0x32,0xC0,0x83,0x7E,0x1A,0x00,0x75,0x0E,0x8B,0x5E,0x40,0x43,0x80,
+0xE3,0xFE,0x3B,0x5E,0x08,0x75,0x02,0x0C,0x01,0x83,0x7E,0x3A,0x00,0x75,0x0D,0x1E,
+0xC5,0x5E,0x14,0x8B,0x1F,0x1F,0x85,0xDB,0x75,0x02,0x0C,0x02,0xF7,0x46,0x38,0x10,
+0x00,0x74,0x02,0x0C,0x04,0x8B,0x5E,0x7A,0xF7,0xC3,0x02,0x00,0x74,0x02,0x0C,0x08,
+0xF7,0xC3,0x04,0x00,0x74,0x02,0x0C,0x10,0xF7,0xC3,0x08,0x00,0x74,0x02,0x0C,0x20,
+0xF7,0xC3,0x40,0x00,0x74,0x02,0x0C,0x40,0x88,0x86,0xBF,0x00,0xC3,0x90,0x6A,0x00,
+0x1F,0xC6,0x06,0x93,0x12,0x0D,0x9C,0x0E,0xE8,0xF1,0xEB,0x90,0xB0,0x02,0xE6,0xDA,
+0xF8,0xC3,0x33,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x01,0xE6,0xD8,0xF8,0xC3,0x33,0xC0,
+0xE6,0xD8,0xF8,0xC3,0xB0,0xFF,0xE8,0x4E,0xFA,0xE8,0xA1,0xFA,0xF8,0xC3,0xAC,0x49,
+0xE8,0xAF,0xFB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x15,0xFD,0xF8,0xC3,0x90,0xAC,0x49,
+0xE8,0x67,0xFD,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x1F,0xFD,0xF8,0xC3,0x90,0xAC,0x49,
+0xE6,0x34,0xF8,0xC3,0xAC,0x49,0xE6,0x36,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x77,0x1F,
+0x84,0xC0,0x75,0x1D,0xE4,0x14,0x24,0xEF,0xE6,0x14,0xE4,0x12,0x24,0x3F,0xE6,0x12,
+0xE4,0x16,0xA8,0x04,0x74,0x09,0xE8,0xEA,0xF9,0x72,0x04,0xB0,0x18,0xE6,0x0A,0xF8,
+0xC3,0x8A,0xE0,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,0x12,0x0C,0xC0,0xF6,0xC4,0x01,
+0x74,0x02,0x24,0x7F,0xE6,0x12,0xF8,0xC3,0xAC,0x49,0xE8,0x25,0xFD,0xF8,0xC3,0x90,
+0xB8,0x00,0x40,0xE8,0x7D,0xFD,0xE8,0xB4,0xFD,0xE8,0xA8,0xFE,0xB0,0x01,0xE8,0xB9,
+0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x85,0xFD,0xE8,0xA0,0xFD,0xF8,0xC3,0x90,
+0xB8,0x00,0x10,0xE8,0x5D,0xFD,0xE8,0x94,0xFD,0xE8,0x88,0xFE,0xB0,0x08,0xE8,0x99,
+0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x65,0xFD,0xE8,0x80,0xFD,0xF8,0xC3,0x90,
+0xB8,0x00,0x80,0xE8,0x3D,0xFD,0xE8,0x74,0xFD,0xE8,0x68,0xFE,0xB0,0x02,0xE8,0x79,
+0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x45,0xFD,0xE8,0x60,0xFD,0xF8,0xC3,0x90,
+0xB8,0x00,0x20,0xE8,0x1D,0xFD,0xE8,0x54,0xFD,0xE8,0x48,0xFE,0xB0,0x04,0xE8,0x59,
+0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x25,0xFD,0xE8,0x40,0xFD,0xF8,0xC3,0x90,
+0xAC,0x49,0xE8,0x48,0x14,0xE4,0x3C,0x24,0xE7,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90,
+0xB8,0xFC,0x3B,0x89,0x46,0x7C,0xE4,0x3C,0x0C,0x18,0xE6,0x3C,0xF8,0xC3,0xE4,0x12,
+0x0C,0x02,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFD,0xEB,0xF6,0xE8,0xB5,0xFC,0xF8,
+0xC3,0x90,0x83,0x66,0x38,0xFD,0xF8,0xC3,0xAC,0x49,0xA8,0x01,0x74,0x06,0x83,0x4E,
+0x7A,0x20,0xEB,0x04,0x83,0x66,0x7A,0xDF,0xE8,0xCB,0xFB,0xF8,0xC3,0x90,0x8A,0x86,
+0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0x4E,0x26,0x01,
+0x20,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x48,0x08,0x49,0x46,0xF9,0xC3,
 0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0x4E,
-0x26,0x01,0x20,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x48,0x08,0x49,0x46,
-0xF9,0xC3,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,
-0x81,0x4E,0x26,0x01,0x20,0xAC,0xB4,0x0A,0xF6,0xE4,0xEB,0xD8,0xE8,0xFA,0x13,0xE4,
-0x3C,0x24,0xF8,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64,
-0xA9,0x01,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x1A,0xA9,0x04,0x00,0x74,
-0x0F,0xE4,0x3E,0x0C,0x02,0xE6,0x3E,0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x90,
-0xE4,0x3E,0x24,0xFC,0xEB,0xEF,0xE4,0x3E,0x24,0xFC,0xE6,0x3E,0xE8,0x02,0xFD,0xB8,
-0x8C,0x40,0xEB,0xE6,0xE8,0x88,0xF8,0x72,0x05,0xB0,0x18,0xE6,0x0A,0xF8,0xC3,0x90,
-0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90,
-0xE8,0x82,0xFD,0x75,0x06,0x32,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x02,0xE6,0xDA,0x36,
-0xA0,0xB4,0x13,0x24,0x10,0x34,0x10,0xE8,0x16,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,
-0x00,0x74,0x05,0xE8,0xFC,0xFE,0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,
-0x02,0xB0,0x01,0xE8,0xDE,0xFE,0x36,0xA1,0xB4,0x13,0xE8,0xB5,0x13,0xE4,0x3C,0x24,
-0xF8,0x0A,0xC4,0xE6,0x3C,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8,
-0xFA,0xFE,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x73,0xFB,0x32,0xC0,0x36,0x8A,0x26,
+0x26,0x01,0x20,0xAC,0xB4,0x0A,0xF6,0xE4,0xEB,0xD8,0xE8,0xFA,0x13,0xE4,0x3C,0x24,
+0xF8,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64,0xA9,0x01,
+0x00,0x74,0x1B,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x1A,0xA9,0x04,0x00,0x74,0x0F,0xE4,
+0x3E,0x0C,0x02,0xE6,0x3E,0xB8,0x38,0x44,0x89,0x46,0x62,0xF8,0xC3,0x90,0xE4,0x3E,
+0x24,0xFC,0xEB,0xEF,0xE4,0x3E,0x24,0xFC,0xE6,0x3E,0xE8,0xE8,0xFC,0xB8,0xAA,0x40,
+0xEB,0xE6,0xE8,0x6E,0xF8,0x72,0x05,0xB0,0x18,0xE6,0x0A,0xF8,0xC3,0x90,0xAC,0x49,
+0xE8,0xCF,0xF9,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xCF,0xF9,0xF8,0xC3,0x90,0xE8,0x68,
+0xFD,0x75,0x06,0x32,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x02,0xE6,0xDA,0x36,0xA0,0xB4,
+0x13,0x24,0x10,0x34,0x10,0xE8,0x16,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74,
+0x05,0xE8,0xFC,0xFE,0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0,
+0x01,0xE8,0xDE,0xFE,0x36,0xA1,0xB4,0x13,0xE8,0xB5,0x13,0xE4,0x3C,0x24,0xF8,0x0A,
+0xC4,0xE6,0x3C,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8,0xFA,0xFE,
+0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x59,0xFB,0x32,0xC0,0x36,0x8A,0x26,0xB5,0x13,
+0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,0xFE,0xC0,0xE8,0xDB,
+0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x57,0xF9,0x36,0xA1,0xB6,0x13,0xC1,
+0xE8,0x04,0x25,0x03,0x00,0xE8,0xB8,0xFA,0x36,0xA1,0xB6,0x13,0xC1,0xE8,0x05,0x25,
+0x02,0x00,0xE8,0x05,0xFB,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04,0x32,0xC0,
+0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0xAC,0xFA,0x36,0xF6,
+0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x83,0xFE,0xEB,0x03,0xE8,0x84,0xFE,0x36,0xF6,
+0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x65,0xFE,0xEB,0x03,0xE8,0x68,0xFE,0xF8,0xC3,
+0xE4,0x12,0x0C,0x01,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFE,0xEB,0xF6,0xE4,0x14,
+0x24,0xF0,0x0C,0x05,0xE6,0x14,0xE4,0x2A,0x24,0xF0,0x0C,0x06,0xE6,0x2A,0xF8,0xC3,
+0xE4,0x2A,0x24,0xF0,0xE6,0x2A,0xE4,0x14,0x24,0xF0,0x0C,0x07,0xE6,0x14,0xF8,0xC3,
+0xAD,0x49,0x49,0xE8,0x64,0xF9,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8,
+0x58,0xF9,0x89,0x86,0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0xA8,0xF7,0xF8,
+0xC3,0x90,0x83,0x66,0x26,0xFB,0xE8,0x9E,0xF7,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0,
+0x75,0x0D,0xE4,0x10,0x24,0xEF,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xF8,0xC3,0xE4,
+0x10,0x0C,0x10,0xEB,0xF1,0x90,0xAC,0x49,0x3C,0x02,0x76,0x02,0x32,0xC0,0xC0,0xE0,
+0x04,0xA8,0x20,0x74,0x02,0x0C,0x08,0x24,0x18,0x8A,0xE0,0xE4,0x12,0x24,0xE7,0x0A,
+0xC4,0xE6,0x12,0x80,0x8E,0xA1,0x00,0x44,0xF8,0xC3,0xAC,0x49,0x88,0x86,0xC0,0x00,
+0xF8,0xC3,0xAC,0x49,0xE6,0x3A,0xF8,0xC3,0xAC,0x49,0x84,0xC0,0x74,0x08,0xE4,0x12,
+0x0C,0x04,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFB,0xEB,0xF6,0xAC,0x49,0xE8,0xD6,
+0xF6,0x73,0x03,0xE8,0x27,0xF7,0xF8,0xC3,0xE4,0x12,0xA8,0x02,0x74,0x04,0x24,0xFD,
+0xE6,0x12,0xB8,0xF0,0x00,0xE8,0x87,0xFA,0x81,0x66,0x26,0xFF,0xF3,0xE8,0x57,0xF7,
+0xE8,0x9A,0xFA,0xF8,0xC3,0x90,0xB8,0x80,0x00,0xE8,0x57,0xFA,0x80,0x4E,0x27,0x08,
+0xE8,0x44,0xF7,0xE8,0x87,0xFA,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x61,0xFA,0x81,0x66,
+0x26,0xFF,0xF7,0xE8,0x31,0xF7,0xE8,0x74,0xFA,0xF8,0xC3,0x90,0xB8,0x10,0x00,0xE8,
+0x31,0xFA,0x80,0x4E,0x27,0x04,0xE8,0x1E,0xF7,0xE8,0x61,0xFA,0xF8,0xC3,0xB8,0x10,
+0x00,0xE8,0x3B,0xFA,0x81,0x66,0x26,0xFF,0xFB,0xE8,0x0B,0xF7,0xE8,0x4E,0xFA,0xF8,
+0xC3,0x90,0x33,0xC0,0xAC,0x49,0x3C,0x01,0x73,0x04,0xB0,0x01,0xEB,0x06,0x3C,0x0C,
+0x76,0x02,0xB0,0x0C,0x89,0x46,0x1C,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x20,0x8A,
+0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x83,0x4E,0x26,
+0x01,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,
+0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x90,0xAC,0x49,0x50,0xE8,0x05,0xF6,0x58,0x72,
+0x08,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF8,0xC3,0xF9,0xC3,0x90,0xAC,0x50,0xAD,0xE8,
+0x82,0xF8,0x5A,0xF6,0xC2,0x01,0x74,0x12,0x39,0x86,0x96,0x00,0x74,0x0C,0x89,0x86,
+0x96,0x00,0xE6,0xF0,0x86,0xE0,0xE6,0xF8,0x86,0xE0,0xF6,0xC2,0x02,0x74,0x10,0x39,
+0x86,0x94,0x00,0x74,0x0A,0x89,0x86,0x94,0x00,0xE6,0xE4,0x86,0xE0,0xE6,0xEC,0x83,
+0xE9,0x03,0xC3,0x90,0xE4,0x16,0x88,0x86,0xBC,0x00,0xE8,0xE6,0xFA,0x33,0xDB,0xE4,
+0x0C,0xA8,0x06,0x74,0x03,0x80,0xCB,0x01,0xA8,0x10,0x74,0x03,0x80,0xCB,0x02,0xA8,
+0x80,0x74,0x03,0x80,0xCB,0x04,0xE4,0x12,0x8A,0xE0,0x24,0x18,0x0A,0xD8,0xE4,0xDA,
+0xF6,0xC4,0x02,0x74,0x07,0xA8,0x40,0x75,0x03,0x80,0xCB,0x20,0xA8,0x02,0x75,0x09,
+0xE4,0x2A,0xA8,0x0F,0x74,0x03,0x80,0xCB,0x40,0xF7,0x46,0x38,0x02,0x00,0x74,0x09,
+0xE4,0xD8,0xA8,0x01,0x75,0x03,0x80,0xCB,0x80,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4,
+0x00,0xB0,0x0A,0xE8,0x5C,0xE4,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x74,0x41,0x77,0x1F,
+0x50,0xE8,0x4F,0xF5,0x58,0x72,0x0C,0x84,0xC0,0x74,0x0A,0xB0,0x12,0xE6,0x0A,0x80,
+0x4E,0x38,0x01,0xF8,0xC3,0xB0,0x11,0xE6,0x0A,0x80,0x66,0x38,0xFE,0xF8,0xC3,0x8B,
+0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04,0x75,0xE6,0x8A,0x86,0xA5,
+0x00,0xA8,0x10,0x75,0xDE,0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x81,
+0x4E,0x38,0x00,0x08,0x8A,0x86,0xA5,0x00,0xA8,0x10,0x74,0xC7,0x24,0xEF,0xEB,0xE7,
+0xAD,0x49,0x49,0x3C,0x01,0x72,0x11,0x3C,0x0C,0x77,0x0D,0x50,0x8A,0xE0,0xE4,0x14,
+0x25,0xF0,0x0F,0x0A,0xC4,0xE6,0x14,0x58,0x8A,0xC4,0x84,0xC0,0x74,0x02,0xE6,0x42,
+0xF8,0xC3,0xE8,0xCF,0xF9,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xD4,0xE3,0xF8,0xC3,
+0x3A,0x86,0xAF,0x00,0x74,0x1F,0x88,0x86,0xAF,0x00,0x8A,0xE0,0x80,0xC2,0x06,0xB0,
+0xBF,0xEE,0x80,0xEA,0x02,0x8A,0xC4,0xEE,0x8A,0x86,0xA8,0x00,0x80,0xC2,0x02,0xEE,
+0x80,0xEA,0x06,0x8A,0xC4,0xC3,0x8B,0x46,0x3E,0x85,0xC0,0x8A,0x86,0xA5,0x00,0x74,
+0x12,0xA8,0x08,0x75,0x0D,0x0C,0x08,0x88,0x86,0xA5,0x00,0x80,0xC2,0x02,0xEE,0x80,
+0xEA,0x02,0xC3,0xA8,0x08,0x74,0xFB,0x24,0xF7,0xEB,0xEC,0x8B,0x46,0x26,0x84,0xC0,
+0x74,0x16,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x0D,0x24,0xFD,0x88,0x86,0xA5,0x00,
+0x83,0xC2,0x02,0xEE,0x83,0xEA,0x02,0xC3,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x75,0xF7,
+0x0C,0x02,0xEB,0xE8,0x52,0x83,0xC2,0x0C,0xEC,0xC0,0xE8,0x04,0x88,0x86,0xA9,0x00,
+0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,0xA8,0x08,0x75,0x03,0x80,
+0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x02,0x75,0x03,0x80,0xCB,0x80,0x88,0x5E,
+0x26,0x8A,0x86,0xA5,0x00,0x84,0xDB,0x74,0x10,0xA8,0x02,0x74,0x0A,0x24,0xFD,0x88,
+0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x5A,0xC3,0xA8,0x02,0x75,0xFA,0x0C,0x02,0xEB,
+0xEE,0x90,0xFF,0xFF,0x00,0x48,0x00,0x30,0xBA,0x20,0xC4,0x1A,0x00,0x18,0x00,0x12,
+0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x02,0x80,0x01,0xC0,0x00,0x60,0x00,0x30,0x00,
+0x18,0x00,0xCD,0x01,0x00,0x01,0x80,0x00,0x10,0x00,0x10,0x00,0x0E,0x00,0x0C,0x00,
+0x08,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x03,0x00,0x02,0x00,0x01,0x00,
+0x52,0x51,0x56,0x3C,0x1E,0x77,0x47,0x98,0x8B,0xF0,0x8A,0x82,0xC4,0x00,0x32,0xE4,
+0x83,0xFE,0x18,0x74,0x3D,0x83,0xFE,0x19,0x74,0x3E,0x83,0xFE,0x1E,0x77,0x2F,0xD1,
+0xE6,0x2E,0x8B,0x8C,0x32,0x2D,0x3B,0x8E,0x94,0x00,0x74,0x22,0x89,0x8E,0x94,0x00,
+0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A,
+0xC1,0xEE,0x83,0xC2,0x02,0x8A,0xC5,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5E,0x59,
+0x5A,0xC3,0x8B,0x8E,0x8E,0x00,0xEB,0xCE,0x8B,0x8E,0x90,0x00,0xEB,0xC8,0x52,0x51,
+0x3D,0x05,0x00,0x77,0x03,0xB8,0x05,0x00,0x8B,0xC8,0xBA,0x02,0x00,0xB8,0x00,0xD0,
+0xF7,0xF1,0x05,0x01,0x00,0xD1,0xE8,0x59,0x5A,0xC3,0x8B,0x46,0x7A,0xA8,0x20,0x74,
+0x0B,0x80,0xBE,0xC3,0x00,0x03,0x75,0x04,0x0C,0x01,0xEB,0x02,0x24,0xFE,0x89,0x46,
+0x7A,0xC3,0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xA6,0xA8,0x00,0x8A,0xDC,0x80,0xE4,
+0xFC,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06,0xEE,0x83,
+0xEA,0x06,0xE8,0xC5,0xFF,0xC3,0x00,0x08,0x18,0x38,0x28,0x90,0x3C,0x04,0x77,0x23,
+0x32,0xE4,0x8B,0xD8,0x2E,0x8A,0x87,0x26,0x2E,0x8A,0xA6,0xA8,0x00,0x8A,0xDC,0x80,
+0xE4,0xC7,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06,0xEE,
+0x83,0xEA,0x06,0xC3,0x84,0xC0,0x74,0x02,0xB0,0x04,0x8A,0xA6,0xA8,0x00,0x8A,0xDC,
+0x80,0xE4,0xFB,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06,
+0xEE,0x83,0xEA,0x06,0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x34,0x3C,0x02,0x74,
+0x3B,0x8A,0x86,0xAF,0x00,0x0C,0x04,0xE8,0xE6,0xFD,0x8B,0x46,0x2E,0x3B,0x46,0x3C,
+0x77,0x1B,0xF7,0xC3,0x00,0x04,0x75,0x15,0x81,0xCB,0x00,0x04,0x83,0xC2,0x02,0x8A,
+0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0x89,0x5E,0x38,
+0xC3,0x8A,0x86,0xAF,0x00,0x24,0xFB,0xE8,0xB6,0xFD,0xEB,0xF1,0xF7,0xC3,0x10,0x00,
+0x74,0xEF,0xEB,0xED,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04,0x88,0x86,
+0xA9,0x00,0xC3,0x90,0x8A,0x86,0xA7,0x00,0x0C,0x01,0x88,0x86,0xA7,0x00,0x8B,0xDA,
+0x80,0xC2,0x08,0xEE,0x8B,0xD3,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x24,0xFE,0xEB,0xEA,
+0x8A,0x86,0xA7,0x00,0x0C,0x02,0xEB,0xE2,0x8A,0x86,0xA7,0x00,0x24,0xFD,0xEB,0xDA,
+0xB0,0xFF,0xE8,0x52,0xF2,0xE8,0x97,0xF2,0xF8,0xC3,0xAC,0x49,0xE8,0x61,0xFE,0xF8,
+0xC3,0x90,0xAC,0x49,0xE8,0xEB,0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x35,0xFF,0xF8,
+0xC3,0x90,0xAC,0x49,0xE8,0x05,0xFF,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,
+0xEE,0x52,0x83,0xC2,0x02,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8,
+0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x06,0xEB,0xE6,0x90,
+0xAC,0x49,0x3C,0x02,0x77,0x0D,0x84,0xC0,0x75,0x0B,0x8A,0x86,0xAF,0x00,0x24,0xFD,
+0xE8,0x0D,0xFD,0xF8,0xC3,0x50,0x8A,0x86,0xAF,0x00,0x0C,0x02,0xE8,0x01,0xFD,0x5B,
+0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0xF6,0xC3,0x01,0x74,0x0C,0x24,0xDF,0x88,0x86,
+0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x0C,0x20,0xEB,0xF2,0xAC,0x49,0xE8,0xE5,
+0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x69,0xF5,0xE8,0xF9,0xFC,0xE8,0x24,0xFF,
+0xB0,0x01,0xE8,0xA5,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x71,0xF5,0xE8,0xE5,
+0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x49,0xF5,0xE8,0xD9,0xFC,0xE8,0x04,0xFF,
+0xB0,0x08,0xE8,0x85,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x51,0xF5,0xE8,0xC5,
+0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x29,0xF5,0xE8,0xB9,0xFC,0xE8,0xE4,0xFE,
+0xB0,0x02,0xE8,0x65,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x31,0xF5,0xE8,0xA5,
+0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x09,0xF5,0xE8,0x99,0xFC,0xE8,0xC4,0xFE,
+0xB0,0x04,0xE8,0x45,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x11,0xF5,0xE8,0x85,
+0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x34,0x0C,0xF8,0xC3,0x90,0xB8,0xFC,0x3B,0x89,
+0x46,0x7C,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x0C,0x80,0xE8,0x43,0xFC,0xF8,0xC3,0x90,
+0x8A,0x86,0xAF,0x00,0x24,0x7F,0xEB,0xF2,0x8A,0x86,0xAF,0x00,0x0C,0x40,0xE8,0x2F,
+0xFC,0xF8,0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0xBF,0xEB,0xF2,0xAC,0x49,0xA8,0x01,
+0x74,0x07,0x83,0x4E,0x7A,0x20,0xEB,0x05,0x90,0x83,0x66,0x7A,0xDF,0xE8,0x8A,0xFD,
+0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,
+0x83,0xEA,0x06,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x26,0x01,0x83,0x4E,
+0x48,0x08,0xB0,0x06,0xE8,0xBB,0xDF,0x49,0x46,0xF9,0xC3,0x90,0x83,0xC2,0x06,0x8A,
+0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x06,0xAC,0xB4,0x0A,
+0xF6,0xE4,0xEB,0xD0,0xE8,0xE0,0x0B,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64,
+0xA9,0x01,0x00,0x74,0x19,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x0A,0xA9,0x04,0x00,0x74,
+0x0D,0xB8,0xE2,0x3F,0xEB,0x0B,0xE8,0xEC,0xF4,0xB8,0xAA,0x40,0xEB,0x03,0xB8,0x38,
+0x44,0x89,0x46,0x62,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0xA8,0x02,0x74,0x0A,0x24,0xFD,
+0xE8,0x8D,0xFB,0x0C,0x02,0xE8,0x88,0xFB,0xF8,0xC3,0xAC,0x49,0xE8,0x81,0xFC,0xF8,
+0xC3,0x90,0xAC,0x49,0xE8,0x79,0xFC,0xF8,0xC3,0x90,0xE8,0x5C,0xF5,0x75,0x05,0xE8,
+0xE6,0xFD,0xF8,0xC3,0xE8,0xCD,0xFD,0x36,0xA0,0xB4,0x13,0x24,0x10,0x34,0x10,0xE8,
+0x26,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74,0x05,0xE8,0xFE,0xFE,0xEB,0x0E,
+0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0,0x01,0xE8,0xE8,0xFE,0x36,0xA1,
+0xB4,0x13,0xE8,0xAB,0x0B,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8,
+0x0C,0xFF,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x2B,0xFD,0x32,0xC0,0x36,0x8A,0x26,
 0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,0xFE,0xC0,
-0xE8,0xDB,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x71,0xF9,0x36,0xA1,0xB6,
-0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0xD2,0xFA,0x36,0xA1,0xB6,0x13,0xC1,0xE8,
-0x05,0x25,0x02,0x00,0xE8,0x1F,0xFB,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04,
-0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0xC6,0xFA,
-0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x83,0xFE,0xEB,0x03,0xE8,0x84,0xFE,
-0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x65,0xFE,0xEB,0x03,0xE8,0x68,0xFE,
-0xF8,0xC3,0xE4,0x12,0x0C,0x01,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFE,0xEB,0xF6,
-0xE4,0x14,0x24,0xF0,0x0C,0x05,0xE6,0x14,0xE4,0x2A,0x24,0xF0,0x0C,0x06,0xE6,0x2A,
-0xF8,0xC3,0xE4,0x2A,0x24,0xF0,0xE6,0x2A,0xE4,0x14,0x24,0xF0,0x0C,0x07,0xE6,0x14,
-0xF8,0xC3,0xAD,0x49,0x49,0xE8,0x7E,0xF9,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,
-0x49,0xE8,0x72,0xF9,0x89,0x86,0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0xC2,
-0xF7,0xF8,0xC3,0x90,0x83,0x66,0x26,0xFB,0xE8,0xB8,0xF7,0xF8,0xC3,0x90,0xAC,0x49,
-0x84,0xC0,0x75,0x0D,0xE4,0x10,0x24,0xEF,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xF8,
-0xC3,0xE4,0x10,0x0C,0x10,0xEB,0xF1,0x90,0xAC,0x49,0x3C,0x02,0x76,0x02,0x32,0xC0,
-0xC0,0xE0,0x04,0xA8,0x20,0x74,0x02,0x0C,0x08,0x24,0x18,0x8A,0xE0,0xE4,0x12,0x24,
-0xE7,0x0A,0xC4,0xE6,0x12,0x80,0x8E,0xA1,0x00,0x44,0xF8,0xC3,0xAC,0x49,0x88,0x86,
-0xC0,0x00,0xF8,0xC3,0xAC,0x49,0xE6,0x3A,0xF8,0xC3,0xAC,0x49,0x84,0xC0,0x74,0x08,
-0xE4,0x12,0x0C,0x04,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFB,0xEB,0xF6,0xAC,0x49,
-0xE8,0xF0,0xF6,0x73,0x03,0xE8,0x41,0xF7,0xF8,0xC3,0xE4,0x12,0xA8,0x02,0x74,0x04,
-0x24,0xFD,0xE6,0x12,0xB8,0xF0,0x00,0xE8,0xA1,0xFA,0x81,0x66,0x26,0xFF,0xF3,0xE8,
-0x71,0xF7,0xE8,0xB4,0xFA,0xF8,0xC3,0x90,0xB8,0x80,0x00,0xE8,0x71,0xFA,0x80,0x4E,
-0x27,0x08,0xE8,0x5E,0xF7,0xE8,0xA1,0xFA,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x7B,0xFA,
-0x81,0x66,0x26,0xFF,0xF7,0xE8,0x4B,0xF7,0xE8,0x8E,0xFA,0xF8,0xC3,0x90,0xB8,0x10,
-0x00,0xE8,0x4B,0xFA,0x80,0x4E,0x27,0x04,0xE8,0x38,0xF7,0xE8,0x7B,0xFA,0xF8,0xC3,
-0xB8,0x10,0x00,0xE8,0x55,0xFA,0x81,0x66,0x26,0xFF,0xFB,0xE8,0x25,0xF7,0xE8,0x68,
-0xFA,0xF8,0xC3,0x90,0x33,0xC0,0xAC,0x49,0x3C,0x01,0x73,0x04,0xB0,0x01,0xEB,0x06,
-0x3C,0x0C,0x76,0x02,0xB0,0x0C,0x89,0x46,0x1C,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,
-0x20,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x83,
-0x4E,0x26,0x01,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,
-0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x90,0xAC,0x49,0x50,0xE8,0x1F,0xF6,
-0x58,0x72,0x08,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF8,0xC3,0xF9,0xC3,0x90,0xAC,0x50,
-0xAD,0xE8,0x9C,0xF8,0x5A,0xF6,0xC2,0x01,0x74,0x12,0x39,0x86,0x96,0x00,0x74,0x0C,
-0x89,0x86,0x96,0x00,0xE6,0xF0,0x86,0xE0,0xE6,0xF8,0x86,0xE0,0xF6,0xC2,0x02,0x74,
-0x10,0x39,0x86,0x94,0x00,0x74,0x0A,0x89,0x86,0x94,0x00,0xE6,0xE4,0x86,0xE0,0xE6,
-0xEC,0x83,0xE9,0x03,0xC3,0x90,0xE4,0x16,0x88,0x86,0xBC,0x00,0xE8,0x00,0xFB,0x33,
-0xDB,0xE4,0x0C,0xA8,0x06,0x74,0x03,0x80,0xCB,0x01,0xA8,0x10,0x74,0x03,0x80,0xCB,
-0x02,0xA8,0x80,0x74,0x03,0x80,0xCB,0x04,0xE4,0x12,0x8A,0xE0,0x24,0x18,0x0A,0xD8,
-0xE4,0xDA,0xF6,0xC4,0x02,0x74,0x07,0xA8,0x40,0x75,0x03,0x80,0xCB,0x20,0xA8,0x02,
-0x75,0x09,0xE4,0x2A,0xA8,0x0F,0x74,0x03,0x80,0xCB,0x40,0xF7,0x46,0x38,0x02,0x00,
-0x74,0x09,0xE4,0xD8,0xA8,0x01,0x75,0x03,0x80,0xCB,0x80,0x88,0x9E,0xBE,0x00,0xFE,
-0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x76,0xE4,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x74,0x41,
-0x77,0x1F,0x50,0xE8,0x69,0xF5,0x58,0x72,0x0C,0x84,0xC0,0x74,0x0A,0xB0,0x12,0xE6,
-0x0A,0x80,0x4E,0x38,0x01,0xF8,0xC3,0xB0,0x11,0xE6,0x0A,0x80,0x66,0x38,0xFE,0xF8,
-0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04,0x75,0xE6,0x8A,
-0x86,0xA5,0x00,0xA8,0x10,0x75,0xDE,0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,
-0xC3,0x81,0x4E,0x38,0x00,0x08,0x8A,0x86,0xA5,0x00,0xA8,0x10,0x74,0xC7,0x24,0xEF,
-0xEB,0xE7,0xAD,0x49,0x49,0x3C,0x01,0x72,0x11,0x3C,0x0C,0x77,0x0D,0x50,0x8A,0xE0,
-0xE4,0x14,0x25,0xF0,0x0F,0x0A,0xC4,0xE6,0x14,0x58,0x8A,0xC4,0x84,0xC0,0x74,0x02,
-0xE6,0x42,0xF8,0xC3,0xE8,0xE9,0xF9,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xEE,0xE3,
-0xF8,0xC3,0x3A,0x86,0xAF,0x00,0x74,0x1F,0x88,0x86,0xAF,0x00,0x8A,0xE0,0x80,0xC2,
-0x06,0xB0,0xBF,0xEE,0x80,0xEA,0x02,0x8A,0xC4,0xEE,0x8A,0x86,0xA8,0x00,0x80,0xC2,
-0x02,0xEE,0x80,0xEA,0x06,0x8A,0xC4,0xC3,0x8B,0x46,0x3E,0x85,0xC0,0x8A,0x86,0xA5,
-0x00,0x74,0x12,0xA8,0x08,0x75,0x0D,0x0C,0x08,0x88,0x86,0xA5,0x00,0x80,0xC2,0x02,
-0xEE,0x80,0xEA,0x02,0xC3,0xA8,0x08,0x74,0xFB,0x24,0xF7,0xEB,0xEC,0x8B,0x46,0x26,
-0x84,0xC0,0x74,0x16,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x0D,0x24,0xFD,0x88,0x86,
-0xA5,0x00,0x83,0xC2,0x02,0xEE,0x83,0xEA,0x02,0xC3,0x8A,0x86,0xA5,0x00,0xA8,0x02,
-0x75,0xF7,0x0C,0x02,0xEB,0xE8,0x52,0x83,0xC2,0x0C,0xEC,0xC0,0xE8,0x04,0x88,0x86,
-0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,0xA8,0x08,0x75,
-0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x02,0x75,0x03,0x80,0xCB,0x80,
-0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0x84,0xDB,0x74,0x10,0xA8,0x02,0x74,0x0A,0x24,
-0xFD,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x5A,0xC3,0xA8,0x02,0x75,0xFA,0x0C,
-0x02,0xEB,0xEE,0x90,0xFF,0xFF,0x00,0x48,0x00,0x30,0xBA,0x20,0xC4,0x1A,0x00,0x18,
-0x00,0x12,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x02,0x80,0x01,0xC0,0x00,0x60,0x00,
-0x30,0x00,0x18,0x00,0xCD,0x01,0x00,0x01,0x80,0x00,0x10,0x00,0x10,0x00,0x0E,0x00,
-0x0C,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x03,0x00,0x02,0x00,
-0x01,0x00,0x52,0x51,0x56,0x3C,0x1E,0x77,0x47,0x98,0x8B,0xF0,0x8A,0x82,0xC4,0x00,
-0x32,0xE4,0x83,0xFE,0x18,0x74,0x3D,0x83,0xFE,0x19,0x74,0x3E,0x83,0xFE,0x1E,0x77,
-0x2F,0xD1,0xE6,0x2E,0x8B,0x8C,0x14,0x2D,0x3B,0x8E,0x94,0x00,0x74,0x22,0x89,0x8E,
-0x94,0x00,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,
-0x06,0x8A,0xC1,0xEE,0x83,0xC2,0x02,0x8A,0xC5,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,
-0x5E,0x59,0x5A,0xC3,0x8B,0x8E,0x8E,0x00,0xEB,0xCE,0x8B,0x8E,0x90,0x00,0xEB,0xC8,
-0x52,0x51,0x3D,0x05,0x00,0x77,0x03,0xB8,0x05,0x00,0x8B,0xC8,0xBA,0x02,0x00,0xB8,
-0x00,0xD0,0xF7,0xF1,0x05,0x01,0x00,0xD1,0xE8,0x59,0x5A,0xC3,0x8B,0x46,0x7A,0xA8,
-0x20,0x74,0x0B,0x80,0xBE,0xC3,0x00,0x03,0x75,0x04,0x0C,0x01,0xEB,0x02,0x24,0xFE,
-0x89,0x46,0x7A,0xC3,0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xA6,0xA8,0x00,0x8A,0xDC,
-0x80,0xE4,0xFC,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06,
-0xEE,0x83,0xEA,0x06,0xE8,0xC5,0xFF,0xC3,0x00,0x08,0x18,0x38,0x28,0x90,0x3C,0x04,
-0x77,0x23,0x32,0xE4,0x8B,0xD8,0x2E,0x8A,0x87,0x08,0x2E,0x8A,0xA6,0xA8,0x00,0x8A,
-0xDC,0x80,0xE4,0xC7,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,
-0x06,0xEE,0x83,0xEA,0x06,0xC3,0x84,0xC0,0x74,0x02,0xB0,0x04,0x8A,0xA6,0xA8,0x00,
-0x8A,0xDC,0x80,0xE4,0xFB,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,
-0xC2,0x06,0xEE,0x83,0xEA,0x06,0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x34,0x3C,
-0x02,0x74,0x3B,0x8A,0x86,0xAF,0x00,0x0C,0x04,0xE8,0xE6,0xFD,0x8B,0x46,0x2E,0x3B,
-0x46,0x3C,0x77,0x1B,0xF7,0xC3,0x00,0x04,0x75,0x15,0x81,0xCB,0x00,0x04,0x83,0xC2,
-0x02,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0x89,
-0x5E,0x38,0xC3,0x8A,0x86,0xAF,0x00,0x24,0xFB,0xE8,0xB6,0xFD,0xEB,0xF1,0xF7,0xC3,
-0x10,0x00,0x74,0xEF,0xEB,0xED,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04,
-0x88,0x86,0xA9,0x00,0xC3,0x90,0x8A,0x86,0xA7,0x00,0x0C,0x01,0x88,0x86,0xA7,0x00,
-0x8B,0xDA,0x80,0xC2,0x08,0xEE,0x8B,0xD3,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x24,0xFE,
-0xEB,0xEA,0x8A,0x86,0xA7,0x00,0x0C,0x02,0xEB,0xE2,0x8A,0x86,0xA7,0x00,0x24,0xFD,
-0xEB,0xDA,0xB0,0xFF,0xE8,0x6C,0xF2,0xE8,0xB1,0xF2,0xF8,0xC3,0xAC,0x49,0xE8,0x61,
-0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xEB,0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x35,
-0xFF,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x05,0xFF,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,
-0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x02,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,
-0x5A,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x06,0xEB,
-0xE6,0x90,0xAC,0x49,0x3C,0x02,0x77,0x0D,0x84,0xC0,0x75,0x0B,0x8A,0x86,0xAF,0x00,
-0x24,0xFD,0xE8,0x0D,0xFD,0xF8,0xC3,0x50,0x8A,0x86,0xAF,0x00,0x0C,0x02,0xE8,0x01,
-0xFD,0x5B,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0xF6,0xC3,0x01,0x74,0x0C,0x24,0xDF,
-0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x0C,0x20,0xEB,0xF2,0xAC,0x49,
-0xE8,0xE5,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x83,0xF5,0xE8,0xF9,0xFC,0xE8,
-0x24,0xFF,0xB0,0x01,0xE8,0xBF,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x8B,0xF5,
-0xE8,0xE5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x63,0xF5,0xE8,0xD9,0xFC,0xE8,
-0x04,0xFF,0xB0,0x08,0xE8,0x9F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x6B,0xF5,
-0xE8,0xC5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x43,0xF5,0xE8,0xB9,0xFC,0xE8,
-0xE4,0xFE,0xB0,0x02,0xE8,0x7F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x4B,0xF5,
-0xE8,0xA5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x23,0xF5,0xE8,0x99,0xFC,0xE8,
-0xC4,0xFE,0xB0,0x04,0xE8,0x5F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x2B,0xF5,
-0xE8,0x85,0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x34,0x0C,0xF8,0xC3,0x90,0xB8,0xDE,
-0x3B,0x89,0x46,0x7C,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x0C,0x80,0xE8,0x43,0xFC,0xF8,
-0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0x7F,0xEB,0xF2,0x8A,0x86,0xAF,0x00,0x0C,0x40,
-0xE8,0x2F,0xFC,0xF8,0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0xBF,0xEB,0xF2,0xAC,0x49,
-0xA8,0x01,0x74,0x07,0x83,0x4E,0x7A,0x20,0xEB,0x05,0x90,0x83,0x66,0x7A,0xDF,0xE8,
-0x8A,0xFD,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,
-0x00,0xEE,0x83,0xEA,0x06,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x26,0x01,
-0x83,0x4E,0x48,0x08,0xB0,0x06,0xE8,0xD5,0xDF,0x49,0x46,0xF9,0xC3,0x90,0x83,0xC2,
-0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x06,0xAC,
-0xB4,0x0A,0xF6,0xE4,0xEB,0xD0,0xE8,0xE0,0x0B,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,
-0x46,0x64,0xA9,0x01,0x00,0x74,0x19,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x0A,0xA9,0x04,
-0x00,0x74,0x0D,0xB8,0xC4,0x3F,0xEB,0x0B,0xE8,0x06,0xF5,0xB8,0x8C,0x40,0xEB,0x03,
-0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0xA8,0x02,0x74,0x0A,
-0x24,0xFD,0xE8,0x8D,0xFB,0x0C,0x02,0xE8,0x88,0xFB,0xF8,0xC3,0xAC,0x49,0xE8,0x81,
-0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x79,0xFC,0xF8,0xC3,0x90,0xE8,0x76,0xF5,0x75,
-0x05,0xE8,0xE6,0xFD,0xF8,0xC3,0xE8,0xCD,0xFD,0x36,0xA0,0xB4,0x13,0x24,0x10,0x34,
-0x10,0xE8,0x26,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74,0x05,0xE8,0xFE,0xFE,
-0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0,0x01,0xE8,0xE8,0xFE,
-0x36,0xA1,0xB4,0x13,0xE8,0xAB,0x0B,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,
-0x00,0xE8,0x0C,0xFF,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x2B,0xFD,0x32,0xC0,0x36,
-0x8A,0x26,0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,
-0xFE,0xC0,0xE8,0xEF,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x03,0xFC,0x36,
-0xA1,0xB6,0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0x88,0xFC,0x36,0xA1,0xB6,0x13,
-0xC1,0xE8,0x05,0x25,0x02,0x00,0xE8,0xCD,0xFC,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,
-0x75,0x04,0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,
-0x8C,0xFC,0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x8D,0xFE,0xEB,0x03,0xE8,
-0x94,0xFE,0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x69,0xFE,0xEB,0x03,0xE8,
-0x70,0xFE,0xF8,0xC3,0xF8,0xC3,0x8B,0x46,0x38,0xA9,0x04,0x00,0x75,0x23,0x0D,0x04,
-0x00,0x89,0x46,0x38,0x83,0xC2,0x08,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x73,0x14,0x83,
-0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,
-0x08,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEB,0xEE,0x90,0x8B,0x46,0x38,0xA9,
-0x04,0x00,0x74,0x06,0x25,0xFB,0xFF,0x89,0x46,0x38,0xF8,0xC3,0xAD,0x49,0x49,0xE8,
-0xBE,0xFB,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xB2,0xFB,0x89,0x86,
-0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0x92,0xFA,0xF8,0xC3,0x90,0x83,0x66,
-0x26,0xFB,0xE8,0x88,0xFA,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x80,0x8E,
-0xA3,0x00,0x04,0xF8,0xC3,0x80,0xA6,0xA3,0x00,0xFB,0xF8,0xC3,0xAC,0x49,0x83,0xC2,
-0x08,0x3C,0x02,0x76,0x02,0x32,0xC0,0x3C,0x01,0x74,0x12,0x77,0x0B,0x8A,0x86,0xA7,
-0x00,0x24,0xEF,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x8A,0x86,0xA7,
-0x00,0x0C,0x10,0xEB,0xEE,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,
-0x04,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8,0xC3,0x90,0x52,0x83,
-0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x08,0xEB,0xE6,0x90,0xAC,0x49,0xF8,0xC3,
-0xAC,0x49,0xE8,0xCE,0xEE,0x73,0x03,0xE8,0x11,0xEF,0xF8,0xC3,0x8A,0x86,0xAF,0x00,
-0x24,0x7F,0xE8,0xBD,0xF9,0xB8,0xF0,0x00,0xE8,0x80,0xF2,0x81,0x66,0x26,0xFF,0xF3,
-0xE8,0x23,0xFA,0xE8,0xD2,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x51,0xF2,0x80,0x4E,
-0x27,0x08,0xE8,0x11,0xFA,0xE8,0xC0,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x5B,0xF2,
-0x81,0x66,0x26,0xFF,0xF7,0xE8,0xFE,0xF9,0xE8,0xAD,0xF9,0xF8,0xC3,0x90,0xB8,0x10,
-0x00,0xE8,0x2B,0xF2,0x80,0x4E,0x27,0x04,0xE8,0xEB,0xF9,0xE8,0x9A,0xF9,0xF8,0xC3,
-0xB8,0x10,0x00,0xE8,0x19,0xF2,0x81,0x66,0x26,0xFF,0xFB,0xE8,0xD8,0xF9,0xF8,0xC3,
-0xAC,0x49,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,
-0x00,0xEE,0x83,0xEA,0x06,0xF8,0xC3,0x90,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24,
-0xBF,0xEB,0xEA,0x90,0xAC,0x49,0x8A,0xE0,0x80,0xC2,0x0A,0xEC,0x80,0xEA,0x0A,0xA8,
-0x20,0x74,0x05,0x8A,0xC4,0xEE,0xF8,0xC3,0x06,0x51,0x57,0x8B,0x4E,0x24,0xE3,0x34,
-0x49,0x89,0x4E,0x24,0xFF,0x46,0x1A,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0xC4,0xAA,
-0x89,0x7E,0x22,0x8B,0x46,0x26,0x24,0xFD,0x89,0x46,0x26,0x75,0x29,0x8A,0x86,0xA5,
-0x00,0xA8,0x02,0x75,0x21,0x80,0xC2,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x80,
-0xEA,0x02,0xEB,0x12,0xC4,0x7E,0x00,0x3B,0x7E,0x1E,0x76,0x0A,0x4F,0x26,0x88,0x25,
-0x89,0x7E,0x00,0xFF,0x46,0x1A,0x5F,0x59,0x07,0xF8,0xC3,0x90,0xAC,0xAD,0x83,0xE9,
-0x03,0x85,0xC0,0x74,0x05,0x3D,0x00,0x20,0x72,0x05,0xB8,0xFF,0xFF,0xEB,0x03,0xC1,
-0xE0,0x03,0x3B,0x86,0x94,0x00,0x74,0x26,0x89,0x86,0x94,0x00,0x8B,0xD8,0x52,0x83,
-0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A,0xC3,
-0xEE,0x83,0xC2,0x02,0x8A,0xC7,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5A,0xF8,0xC3,
-0xB0,0x88,0x88,0x86,0xBC,0x00,0xE8,0xA6,0xF2,0x33,0xDB,0x8A,0x86,0xA5,0x00,0xA8,
-0x02,0x74,0x03,0x80,0xCB,0x01,0xA8,0x05,0x74,0x03,0x80,0xCB,0x02,0xA8,0x08,0x74,
-0x03,0x80,0xCB,0x04,0xF6,0x86,0xA7,0x00,0x10,0x74,0x03,0x80,0xCB,0x10,0x8A,0x86,
-0xA9,0x00,0xF6,0xC3,0x04,0x75,0x0A,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,
-0x04,0x8A,0xE0,0x8A,0x86,0xAF,0x00,0xA8,0x80,0x74,0x08,0xF6,0xC4,0x01,0x75,0x03,
-0x80,0xCB,0x20,0xF6,0x86,0xA7,0x00,0x02,0x75,0x0A,0xF7,0x46,0x38,0x04,0x00,0x74,
-0x03,0x80,0xCB,0x40,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x0D,
-0xDC,0xF8,0xC3,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x02,0xDC,0xF8,0xC3,0xAC,0x49,
-0x3C,0x02,0x74,0x37,0x77,0x10,0x84,0xC0,0x74,0x06,0x80,0x4E,0x38,0x01,0xF8,0xC3,
-0x80,0x66,0x38,0xFE,0xF8,0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,
-0x00,0x04,0x75,0xEA,0x8A,0x86,0xA5,0x00,0xA8,0x01,0x75,0xE2,0x0C,0x05,0x83,0xC2,
-0x02,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0xF8,0xC3,0x81,0x4E,0x38,0x00,0x08,
-0x8A,0x86,0xA5,0x00,0xA8,0x01,0x74,0xC6,0x24,0xFA,0xEB,0xE2,0xAD,0x49,0x49,0xF8,
-0xC3,0x90,0xE8,0x11,0xFA,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xA0,0xDB,0xF8,0xC3,
-0xB0,0xFF,0xE8,0xD9,0xEC,0xF8,0xC3,0x90,0x83,0x66,0x7A,0xFB,0xB0,0x00,0xE8,0x8D,
-0xDB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x6D,0xD9,0x72,0x11,0x36,0x88,0x1E,0x1A,0x01,
-0x36,0xA0,0x8E,0x12,0x0A,0xC3,0x52,0xBA,0x00,0x01,0xEE,0x5A,0xF8,0xC3,0xAC,0x49,
-0x32,0xE4,0x36,0xA3,0x86,0x12,0x05,0x06,0x00,0x36,0x8B,0x1E,0x88,0x12,0x2B,0xD8,
-0x36,0x89,0x1E,0x8A,0x12,0xF8,0xC3,0x90,0xAD,0x8B,0xD8,0xAD,0x83,0xE9,0x04,0x03,
-0xC3,0x2B,0x46,0x76,0x89,0x46,0x78,0xF7,0x46,0x7A,0x02,0x00,0x74,0x0A,0x83,0x66,
-0x7A,0xFD,0xB8,0x00,0x00,0xE8,0x36,0xDB,0xF8,0xC3,0x06,0x16,0x07,0xAC,0x49,0x25,
-0x0F,0x00,0x6B,0xC0,0x09,0x8D,0xBE,0xFD,0x00,0x03,0xF8,0xAC,0x49,0x25,0x0F,0x00,
-0xAA,0x85,0xC0,0x74,0x08,0x2B,0xC8,0x51,0x8B,0xC8,0xF3,0xA4,0x59,0xE8,0x41,0xF0,
-0xE8,0x44,0x03,0x07,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0xB2,0x13,0x36,0xA3,
-0xB0,0x13,0xF8,0xC3,0x83,0x66,0x7A,0xEF,0xE8,0x2C,0x03,0xF8,0xC3,0x90,0x83,0x4E,
-0x7A,0x10,0xEB,0xF4,0xE8,0xB5,0xF0,0xF8,0xC3,0x90,0xAD,0x3C,0x19,0x77,0x0E,0x3C,
-0x19,0x77,0x0A,0x8B,0xF8,0x81,0xE7,0xFF,0x00,0x88,0xA6,0xC4,0x00,0xF8,0xC3,0x90,
-0x83,0x4E,0x26,0x20,0xAC,0x49,0x32,0xE4,0xD1,0xE0,0x8B,0xD8,0xC1,0xE3,0x02,0x03,
-0xC3,0x89,0x46,0x6E,0x83,0x4E,0x48,0x04,0xB0,0x06,0xE8,0xB1,0xDA,0x49,0x46,0xF9,
-0xC3,0x90,0xFE,0x86,0xB3,0x00,0xB0,0x0A,0xE8,0xA3,0xDA,0xF8,0xC3,0x90,0x33,0xC0,
-0xAC,0x49,0x6B,0xC0,0x0A,0x89,0x86,0x8A,0x00,0xF8,0xC3,0x90,0xAC,0x49,0x32,0xE4,
-0x3D,0x0A,0x00,0x77,0x05,0xB8,0x0A,0x00,0xEB,0x08,0x3D,0x5A,0x00,0x72,0x03,0xB8,
-0x5A,0x00,0x51,0xF7,0xD8,0x05,0x64,0x00,0x8B,0xC8,0x8B,0x46,0x44,0xF7,0xE1,0xB9,
-0x64,0x00,0xF7,0xF1,0x89,0x46,0x46,0x59,0xF8,0xC3,0xAC,0x49,0xE8,0x9F,0xEB,0xF8,
-0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x81,0x66,0x38,0xFF,0xFD,0xF8,0xC3,0x81,
-0x4E,0x38,0x00,0x02,0xF7,0x46,0x38,0x40,0x00,0x75,0x08,0x8A,0x86,0xA9,0x00,0x88,
-0x86,0xAA,0x00,0xF8,0xC3,0x90,0x51,0x56,0xE8,0x7F,0x0C,0x5E,0x59,0xF8,0xC3,0x90,
-0xFE,0x86,0xB6,0x00,0xB0,0x0A,0xE8,0x25,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB7,0x00,
-0xB0,0x0A,0xE8,0x19,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB8,0x00,0xB0,0x0A,0xE8,0x0D,
-0xDA,0xF8,0xC3,0x90,0x00,0x90,0x51,0x55,0xAC,0x2E,0xA2,0x34,0x36,0x33,0xC9,0xAD,
-0x8B,0xF9,0xC1,0xE7,0x05,0xA9,0x01,0x00,0x74,0x23,0x2E,0x8B,0xAD,0x44,0x00,0x83,
-0x7E,0x08,0x00,0x74,0x18,0x2E,0x80,0x3E,0x34,0x36,0x01,0x74,0x09,0x60,0xB0,0x04,
-0xE8,0xBB,0x0C,0x61,0xEB,0x07,0x60,0xB0,0xFB,0xE8,0xEC,0x0C,0x61,0x47,0x47,0xD1,
-0xE8,0x75,0xD2,0x41,0x83,0xF9,0x04,0x72,0xC6,0x5D,0x59,0x83,0xE9,0x05,0xF7,0x46,
-0x38,0x40,0x00,0x74,0x05,0xE8,0xA1,0xEA,0xF8,0xC3,0xE8,0xA7,0xEA,0xF8,0xC3,0x90,
-0x36,0xC6,0x06,0xC8,0x13,0x01,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0x80,0x12,
-0xAC,0x49,0x36,0x2B,0x06,0x88,0x12,0xF7,0xD8,0x36,0xA3,0x82,0x12,0xF8,0xC3,0x90,
-0xC0,0x26,0xC0,0x26,0xCE,0x26,0xD4,0x26,0xDA,0x26,0xE0,0x26,0xE6,0x26,0xF0,0x26,
-0xF8,0x26,0x00,0x27,0x08,0x27,0x10,0x27,0x16,0x27,0xA0,0x34,0xA8,0x34,0xB4,0x34,
-0x1C,0x27,0x5A,0x27,0x62,0x27,0x76,0x27,0x82,0x27,0x96,0x27,0xA2,0x27,0xB6,0x27,
-0xC2,0x27,0xD6,0x27,0xE2,0x27,0xF2,0x27,0xCE,0x34,0xC0,0x26,0x00,0x28,0x08,0x28,
-0x0E,0x28,0x14,0x28,0x1A,0x28,0x30,0x28,0x6C,0x28,0xE8,0x34,0x0A,0x35,0x7A,0x28,
-0xA0,0x28,0xB4,0x28,0xC0,0x28,0xC8,0x28,0x36,0x35,0x44,0x35,0x4E,0x35,0xD0,0x28,
-0xA2,0x29,0xAA,0x29,0xB0,0x29,0xC2,0x29,0x54,0x35,0x5A,0x35,0xD2,0x29,0xDE,0x29,
-0x70,0x35,0xEA,0x29,0xF4,0x29,0xFE,0x29,0x92,0x35,0x18,0x2A,0x9E,0x35,0x3C,0x2A,
-0x44,0x2A,0x4A,0x2A,0xAC,0x35,0x5E,0x2A,0xDA,0x35,0x6A,0x2A,0x88,0x2A,0x9A,0x2A,
-0xAE,0x2A,0xC0,0x2A,0xD4,0x2A,0xE2,0x35,0xEC,0x2A,0x06,0x2B,0x06,0x36,0x1A,0x2B,
-0x2E,0x2B,0x66,0x2B,0x10,0x36,0x1C,0x36,0x28,0x36,0x36,0x36,0xCA,0x2B,0x90,0x36,
-0x22,0x2C,0x44,0x2C,0x98,0x36,0x52,0x28,0xC0,0x26,0xC0,0x26,0xB6,0x2E,0xCA,0x2E,
-0xD2,0x2E,0xDA,0x2E,0xE2,0x2E,0xEC,0x2E,0xF4,0x2E,0xFC,0x2E,0x04,0x2F,0x0C,0x2F,
-0x24,0x2F,0xA0,0x34,0xA8,0x34,0xB4,0x34,0x32,0x2F,0x6E,0x2F,0x76,0x2F,0x8A,0x2F,
-0x96,0x2F,0xAA,0x2F,0xB6,0x2F,0xCA,0x2F,0xD6,0x2F,0xEA,0x2F,0xF6,0x2F,0xFE,0x2F,
-0xCE,0x34,0xC0,0x26,0x06,0x30,0x12,0x30,0x1A,0x30,0x26,0x30,0x2E,0x30,0x44,0x30,
-0x86,0x30,0xE8,0x34,0x0A,0x35,0x8C,0x30,0xB0,0x30,0xB8,0x30,0xCC,0x30,0xD4,0x30,
-0x36,0x35,0x44,0x35,0x4E,0x35,0xDC,0x30,0xA4,0x31,0xA4,0x31,0xA6,0x31,0xDC,0x31,
-0x54,0x35,0x5A,0x35,0xEC,0x31,0xF8,0x31,0x70,0x35,0x04,0x32,0x0E,0x32,0x18,0x32,
-0x92,0x35,0x2C,0x32,0x9E,0x35,0x56,0x32,0x6E,0x32,0x7C,0x32,0xAC,0x35,0x80,0x32,
-0xDA,0x35,0x8C,0x32,0xA8,0x32,0xBA,0x32,0xCE,0x32,0xE0,0x32,0xF0,0x32,0xE2,0x35,
-0xF4,0x32,0x08,0x33,0x06,0x36,0x14,0x33,0x7C,0x33,0xC0,0x33,0x10,0x36,0x1C,0x36,
-0x28,0x36,0x36,0x36,0x3E,0x34,0x90,0x36,0x8C,0x34,0x92,0x34,0x98,0x36,0x6E,0x30,
-0xE3,0x28,0xF7,0x46,0x38,0x40,0x00,0x75,0x32,0xE8,0xFD,0xE8,0x33,0xC0,0xAC,0x49,
-0x3D,0x5B,0x00,0x77,0x19,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0xB0,0x36,0x72,0x0B,
-0x85,0xC9,0x75,0xE8,0x8B,0x46,0x48,0xE8,0x1A,0x0C,0xC3,0x4E,0x41,0xC3,0x6A,0x00,
-0x1F,0xC6,0x06,0x93,0x12,0x0C,0x9C,0x0E,0xE8,0x7D,0xDA,0xE8,0xD6,0xE8,0x33,0xC0,
-0xAC,0x49,0x3D,0x5B,0x00,0x77,0xE7,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0x68,0x37,
-0x72,0xD9,0x85,0xC9,0x75,0xE8,0xC3,0xF7,0x46,0x7A,0x10,0x00,0x75,0x0F,0x83,0xBE,
-0x84,0x00,0x00,0x74,0x08,0xB8,0x2A,0x3A,0x89,0x86,0x80,0x00,0xC3,0x81,0xBE,0x80,
-0x00,0xCE,0x3C,0x74,0xF7,0x83,0xBE,0x88,0x00,0x00,0x75,0x05,0xB8,0xCE,0x3C,0xEB,
-0xE7,0xF7,0x46,0x7A,0x08,0x00,0x75,0x40,0x1E,0x60,0x8B,0x8E,0x88,0x00,0x3B,0x4E,
-0x74,0x77,0x33,0x3B,0x4E,0x78,0x77,0x2E,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,
-0x47,0x47,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xF4,0x00,0x8B,0xC1,0xF7,0x46,0x7A,0x01,
-0x00,0x75,0x1D,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,
-0x74,0xB0,0x0C,0xE8,0x58,0xD7,0x61,0x1F,0xC7,0x86,0x88,0x00,0x00,0x00,0xEB,0xAC,
-0xE3,0xE3,0x50,0x90,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD8,0x90,0x8B,0x8E,
-0x88,0x00,0xE3,0x46,0x8B,0x9E,0x8A,0x00,0x85,0xDB,0x74,0x3E,0xBA,0x50,0xFF,0xED,
-0x2B,0x86,0x82,0x00,0x3B,0xC3,0x72,0x37,0x8D,0xB6,0xF4,0x00,0xC4,0x7E,0x10,0x8B,
-0xDF,0x26,0x03,0x3D,0x47,0x47,0x8B,0xC1,0x16,0x1F,0xF7,0x46,0x7A,0x01,0x00,0x75,
-0x24,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC7,
-0x86,0x88,0x00,0x00,0x00,0xB0,0x0C,0xE8,0xF4,0xD6,0x83,0x66,0x7A,0xF7,0xC3,0xB0,
-0x00,0xE8,0xEA,0xD6,0xC3,0xE3,0xDC,0x50,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,
-0xD2,0x90,0x1E,0x60,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xFD,0x00,0x8B,0x86,0x88,0x00,
-0x8B,0x96,0x84,0x00,0x3A,0x04,0x75,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4,
-0x00,0xF3,0xA6,0x74,0x66,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6,
-0xFD,0x00,0x8B,0x96,0x84,0x00,0x3A,0x04,0x73,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,
-0xBE,0xF4,0x00,0xF3,0xA6,0x74,0x76,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,
-0x8D,0xB6,0xF4,0x00,0xAC,0xF7,0x46,0x7A,0x01,0x00,0x74,0x02,0x24,0x7F,0x1E,0xC5,
-0x5E,0x10,0x8B,0x37,0x88,0x40,0x02,0x46,0x89,0x37,0xFF,0x4E,0x78,0xFF,0x46,0x76,
-0xFF,0x4E,0x74,0x1F,0x8B,0x8E,0x88,0x00,0x49,0x89,0x8E,0x88,0x00,0xE3,0x43,0x8D,
-0xB6,0xF4,0x00,0x8B,0xFE,0x46,0xF3,0xA4,0xE9,0x7D,0xFF,0xC5,0x76,0x10,0x8B,0x1C,
-0x85,0xDB,0x74,0x08,0x03,0xF3,0x83,0xC6,0x03,0x83,0xE6,0xFE,0x8B,0x86,0x84,0x00,
-0x2B,0xC2,0xB4,0x80,0x89,0x04,0x46,0x46,0xC7,0x04,0x00,0x00,0x89,0x76,0x10,0x83,
-0x4E,0x7A,0x04,0xC7,0x86,0x88,0x00,0x00,0x00,0x61,0x1F,0xF9,0xC3,0x33,0xC0,0x61,
-0x1F,0xC3,0xB0,0x80,0x84,0xC0,0x61,0x1F,0xC3,0x90,0x8B,0x4E,0x78,0x2B,0x8E,0x88,
-0x00,0x76,0x27,0x89,0xB6,0x8C,0x00,0x8B,0x5E,0x74,0x3B,0xCB,0x72,0x02,0x8B,0xCB,
-0x3B,0xC8,0x72,0x02,0x8B,0xC8,0x8B,0xC1,0xE3,0x44,0x33,0xD2,0x8E,0xC2,0x8B,0xD1,
-0x83,0xBE,0x88,0x00,0x00,0x74,0x06,0xE9,0x8E,0x00,0x33,0xC0,0xC3,0x8B,0x5E,0x10,
-0x03,0x1F,0x43,0x43,0x52,0xF7,0x46,0x7A,0x01,0x00,0x75,0x2A,0xAC,0x8D,0xBE,0xE4,
-0x00,0x8B,0x8E,0x86,0x00,0xF2,0xAE,0x74,0x34,0x88,0x07,0x43,0x4A,0x75,0xED,0x58,
-0x8B,0x5E,0x10,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x8B,0xC6,
-0x2B,0x86,0x8C,0x00,0xC3,0x90,0xAC,0x8D,0xBE,0xE4,0x00,0x8B,0x8E,0x86,0x00,0xF2,
-0xAE,0x74,0x0A,0x24,0x7F,0x88,0x07,0x43,0x4A,0x75,0xEB,0xEB,0xD2,0x88,0x86,0xF4,
-0x00,0xC7,0x86,0x88,0x00,0x01,0x00,0x58,0x2B,0xC2,0x74,0x0E,0x8B,0x5E,0x10,0x01,
-0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x40,0xE8,0x94,0xFE,0x72,0xBE,
-0x4A,0x75,0x15,0x83,0xBE,0x8A,0x00,0x00,0x74,0xB4,0xBA,0x50,0xFF,0xED,0x89,0x86,
-0x82,0x00,0x83,0x4E,0x7A,0x08,0xEB,0xA6,0x8D,0xBE,0xF4,0x00,0x03,0xBE,0x88,0x00,
-0xA4,0xFF,0x86,0x88,0x00,0xE8,0x6A,0xFE,0x72,0x94,0x79,0x06,0x4A,0x74,0x8F,0xE9,
-0x5B,0xFF,0x4A,0x74,0xCE,0xEB,0xE1,0x90,0x50,0xE8,0x2B,0xCC,0x8B,0x46,0x74,0x39,
-0x46,0x72,0x74,0x27,0x1E,0x56,0x51,0x33,0xC9,0xC5,0x76,0x0C,0xAD,0x74,0x10,0x78,
-0x09,0x03,0xC8,0x05,0x01,0x00,0x24,0xFE,0x03,0xF0,0x3B,0x76,0x10,0x76,0xED,0x29,
-0x4E,0x76,0x01,0x4E,0x78,0xE8,0x51,0xCC,0x59,0x5E,0x1F,0x58,0xC3,0x90,0xC4,0x7E,
-0x10,0x26,0x8B,0x1D,0x83,0xC3,0x03,0x26,0x89,0x1D,0x4B,0x03,0xFB,0xAB,0x91,0xAA,
-0xB8,0x03,0x00,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x90,0xC4,0x7E,
-0x10,0x26,0x8B,0x1D,0x43,0x26,0x89,0x1D,0x43,0x03,0xFB,0xAA,0xFF,0x4E,0x78,0xFF,
-0x46,0x76,0xFF,0x4E,0x74,0xC3,0xE8,0xE5,0xFF,0xC3,0x80,0x81,0x84,0x85,0x82,0x83,
-0x86,0x87,0x50,0x53,0x8A,0xDC,0x83,0xE3,0x0E,0xD1,0xEB,0x2E,0x8A,0x87,0x7A,0x3B,
-0x08,0x86,0xB0,0x00,0xFE,0x86,0xB1,0x00,0xB0,0x0A,0xE8,0xA1,0xD4,0x5B,0x58,0xC3,
-0x50,0x8A,0xC8,0xB8,0xFF,0x00,0xE8,0x95,0xFF,0x58,0xC3,0x90,0x8A,0x86,0xBB,0x00,
-0xE8,0xAB,0xFF,0xC3,0xE8,0xCB,0xFF,0xE8,0xF2,0xFF,0xC3,0x90,0xE8,0xC3,0xFF,0xE8,
-0xB4,0xFF,0xC3,0x90,0x33,0xC0,0xE8,0x95,0xFF,0xC3,0xB8,0xFF,0x00,0x33,0xC9,0xE8,
-0x6C,0xFF,0xC3,0x90,0xB8,0xFF,0x01,0xB1,0x10,0xE8,0x62,0xFF,0xC3,0x90,0xC3,0xDE,
-0x3B,0xC4,0x3B,0xD4,0x3B,0xD4,0x3B,0xDE,0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE,
-0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE,0x3B,0xC4,0x3B,0xC4,0x3B,0xC4,0x3B,0x00,
-0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
-0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
-0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x51,
-0x53,0x8B,0x4E,0x38,0x81,0xE1,0xFF,0xEE,0xA8,0x04,0x74,0x04,0x81,0xC9,0x00,0x01,
-0x8A,0xE0,0x80,0xE4,0x03,0x24,0x18,0xD0,0xE4,0x0A,0xC4,0x33,0xDB,0x8A,0xD8,0x2E,
-0x8B,0x87,0xDF,0x3B,0x89,0x46,0x7C,0x2E,0x0B,0x8F,0xFF,0x3B,0x89,0x4E,0x38,0xD1,
-0xEB,0x2E,0x8A,0xA7,0x1F,0x3C,0x5B,0x59,0xC3,0xAC,0x49,0x3C,0x01,0x72,0x1D,0x74,
-0x20,0x3C,0x03,0x72,0x23,0x74,0x28,0x3C,0x08,0x72,0x2B,0x74,0x30,0x3C,0x20,0x72,
-0x37,0x74,0x3A,0xBB,0xBC,0x3B,0x32,0xE4,0x89,0x5E,0x7E,0xC3,0xBB,0x82,0x3B,0xEB,
-0xF5,0xBB,0x76,0x3B,0xB4,0x01,0xEB,0xF0,0xBB,0xDE,0x3B,0xB4,0x02,0xEB,0xE9,0xBB,
-0xC4,0x3B,0xB4,0x03,0xEB,0xE2,0xBB,0xA0,0x3B,0xB4,0x04,0xEB,0xDB,0xBB,0xAC,0x3B,
-0xAC,0x49,0x88,0x86,0xBB,0x00,0xEB,0xCE,0xBB,0xB4,0x3B,0xEB,0xF3,0xBB,0xDE,0x3B,
-0xEB,0xC4,0xA9,0x04,0x00,0x75,0xD1,0xA9,0x08,0x00,0x75,0xDA,0xEB,0xD1,0x8B,0x5E,
-0x74,0x8B,0x4E,0x78,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8,0x72,0x02,0x8B,0xC8,
-0x8B,0xC1,0xE3,0x2C,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47,0xF7,0x46,
-0x7A,0x01,0x00,0x75,0x1C,0xF7,0xC7,0x01,0x00,0x74,0x02,0x49,0xA4,0xD1,0xE9,0xF3,
-0xA5,0x73,0x01,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,
-0xC3,0x50,0x53,0xBB,0x7F,0x7F,0xF7,0xC7,0x01,0x00,0x74,0x05,0x49,0xAC,0x22,0xC3,
-0xAA,0xD1,0xE9,0xE3,0x1D,0x9C,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x14,0xAD,0x23,0xC3,
-0xAB,0x49,0x74,0x0D,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x06,0xAD,0x23,0xC3,0xAB,0xE2,
-0xE5,0x9D,0x73,0x04,0xAC,0x22,0xC3,0xAB,0x5B,0x58,0xEB,0xB8,0xE8,0xE8,0xC9,0x8B,
-0x5E,0x38,0xF7,0xC3,0x10,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x40,0x00,0x74,0x05,0xE8,
-0xD2,0xE3,0xEB,0x03,0xE8,0xC2,0xE3,0x81,0x66,0x38,0xEF,0xFB,0xF6,0xC3,0x10,0x74,
-0x3C,0xF6,0xC3,0x02,0x74,0x06,0xE4,0xD8,0x0C,0x01,0xE6,0xD8,0xF6,0xC3,0x04,0x74,
-0x11,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEE,0x88,0x86,0xA7,0x00,0x83,
-0xEA,0x08,0xF6,0xC3,0x08,0x74,0x0F,0xE8,0xA5,0xE3,0x72,0x0A,0x8A,0x86,0xC0,0x00,
-0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF7,0xC3,0x00,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x00,
-0x08,0x75,0xF9,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0x40,0x75,0x0D,0xA8,0x10,0x75,0xEC,
-0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x01,0x75,0xDF,0x83,0xC2,0x02,
-0x0C,0x05,0xEE,0x88,0x86,0xA5,0x00,0xC3,0xB0,0x00,0xE8,0x61,0xD2,0xEB,0x0F,0xB0,
-0x02,0xE8,0x90,0x0E,0xEB,0x08,0x83,0x66,0x38,0xDF,0x83,0x4E,0x7A,0x02,0x33,0xC0,
-0x8E,0xD8,0xFA,0xA0,0x92,0x12,0x40,0xA2,0x92,0x12,0x3C,0x05,0x72,0x1E,0xC6,0x06,
-0x92,0x12,0x00,0xFB,0xB0,0x01,0xE8,0x6B,0x0E,0xFA,0xA1,0x26,0x01,0x23,0x06,0x2A,
-0x01,0xA8,0x01,0x75,0x07,0xE8,0xE2,0x07,0xE8,0x61,0x09,0x90,0xB0,0x00,0xE8,0x51,
-0xD2,0xFB,0x85,0xED,0x74,0xB9,0xFA,0xF7,0x46,0x7A,0x46,0x00,0x75,0xC0,0x8B,0x46,
-0x78,0x3D,0x0A,0x00,0x72,0xB0,0x8B,0x4E,0x74,0x83,0xF9,0x50,0x72,0x9A,0x83,0x66,
-0x38,0xDF,0xC5,0x76,0x14,0x8B,0x46,0x3A,0x85,0xC0,0x75,0x58,0xAD,0x85,0xC0,0x75,
-0x0F,0xE8,0xF8,0xFE,0xF7,0x46,0x7A,0x08,0x00,0x74,0x93,0xE8,0xA0,0xFA,0xEB,0x8E,
-0x3B,0x76,0x04,0x76,0x21,0xB9,0x02,0x00,0x39,0x4E,0x2E,0x77,0x05,0xC7,0x46,0x2E,
-0x00,0x00,0x56,0x8B,0x76,0x2C,0x89,0x76,0x04,0xC7,0x04,0x00,0x00,0x46,0x46,0x89,
-0x76,0x2C,0x29,0x4E,0x2E,0x5E,0x85,0xC0,0x79,0x17,0xF6,0xC4,0x10,0x74,0x05,0xFF,
-0x56,0x7C,0xEB,0x03,0xFF,0x56,0x7E,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x9F,0xD1,0xEB,
-0x86,0x89,0x46,0x3A,0xFF,0x96,0x80,0x00,0x29,0x46,0x3A,0x89,0x76,0x14,0xB0,0x0C,
-0xE8,0x8B,0xD1,0xE9,0x71,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,
-0x10,0x02,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0xE8,0xEF,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x03,0xFC,0x36,0xA1,0xB6,
+0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0x88,0xFC,0x36,0xA1,0xB6,0x13,0xC1,0xE8,
+0x05,0x25,0x02,0x00,0xE8,0xCD,0xFC,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04,
+0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0x8C,0xFC,
+0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x8D,0xFE,0xEB,0x03,0xE8,0x94,0xFE,
+0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x69,0xFE,0xEB,0x03,0xE8,0x70,0xFE,
+0xF8,0xC3,0xF8,0xC3,0x8B,0x46,0x38,0xA9,0x04,0x00,0x75,0x23,0x0D,0x04,0x00,0x89,
+0x46,0x38,0x83,0xC2,0x08,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x73,0x14,0x83,0x4E,0x38,
+0x10,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,
+0xC3,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEB,0xEE,0x90,0x8B,0x46,0x38,0xA9,0x04,0x00,
+0x74,0x06,0x25,0xFB,0xFF,0x89,0x46,0x38,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xBE,0xFB,
+0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xB2,0xFB,0x89,0x86,0x90,0x00,
+0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0x92,0xFA,0xF8,0xC3,0x90,0x83,0x66,0x26,0xFB,
+0xE8,0x88,0xFA,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x80,0x8E,0xA3,0x00,
+0x04,0xF8,0xC3,0x80,0xA6,0xA3,0x00,0xFB,0xF8,0xC3,0xAC,0x49,0x83,0xC2,0x08,0x3C,
+0x02,0x76,0x02,0x32,0xC0,0x3C,0x01,0x74,0x12,0x77,0x0B,0x8A,0x86,0xA7,0x00,0x24,
+0xEF,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x0C,
+0x10,0xEB,0xEE,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x04,0xAC,
+0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,
+0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x08,0xEB,0xE6,0x90,0xAC,0x49,0xF8,0xC3,0xAC,0x49,
+0xE8,0xB4,0xEE,0x73,0x03,0xE8,0xF7,0xEE,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x24,0x7F,
+0xE8,0xBD,0xF9,0xB8,0xF0,0x00,0xE8,0x66,0xF2,0x81,0x66,0x26,0xFF,0xF3,0xE8,0x23,
+0xFA,0xE8,0xD2,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x37,0xF2,0x80,0x4E,0x27,0x08,
+0xE8,0x11,0xFA,0xE8,0xC0,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x41,0xF2,0x81,0x66,
+0x26,0xFF,0xF7,0xE8,0xFE,0xF9,0xE8,0xAD,0xF9,0xF8,0xC3,0x90,0xB8,0x10,0x00,0xE8,
+0x11,0xF2,0x80,0x4E,0x27,0x04,0xE8,0xEB,0xF9,0xE8,0x9A,0xF9,0xF8,0xC3,0xB8,0x10,
+0x00,0xE8,0xFF,0xF1,0x81,0x66,0x26,0xFF,0xFB,0xE8,0xD8,0xF9,0xF8,0xC3,0xAC,0x49,
+0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,
+0x83,0xEA,0x06,0xF8,0xC3,0x90,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24,0xBF,0xEB,
+0xEA,0x90,0xAC,0x49,0x8A,0xE0,0x80,0xC2,0x0A,0xEC,0x80,0xEA,0x0A,0xA8,0x20,0x74,
+0x05,0x8A,0xC4,0xEE,0xF8,0xC3,0x06,0x51,0x57,0x8B,0x4E,0x24,0xE3,0x34,0x49,0x89,
+0x4E,0x24,0xFF,0x46,0x1A,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0xC4,0xAA,0x89,0x7E,
+0x22,0x8B,0x46,0x26,0x24,0xFD,0x89,0x46,0x26,0x75,0x29,0x8A,0x86,0xA5,0x00,0xA8,
+0x02,0x75,0x21,0x80,0xC2,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x80,0xEA,0x02,
+0xEB,0x12,0xC4,0x7E,0x00,0x3B,0x7E,0x1E,0x76,0x0A,0x4F,0x26,0x88,0x25,0x89,0x7E,
+0x00,0xFF,0x46,0x1A,0x5F,0x59,0x07,0xF8,0xC3,0x90,0xAC,0xAD,0x83,0xE9,0x03,0x85,
+0xC0,0x74,0x05,0x3D,0x00,0x20,0x72,0x05,0xB8,0xFF,0xFF,0xEB,0x03,0xC1,0xE0,0x03,
+0x3B,0x86,0x94,0x00,0x74,0x26,0x89,0x86,0x94,0x00,0x8B,0xD8,0x52,0x83,0xC2,0x06,
+0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A,0xC3,0xEE,0x83,
+0xC2,0x02,0x8A,0xC7,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5A,0xF8,0xC3,0xB0,0x88,
+0x88,0x86,0xBC,0x00,0xE8,0x8C,0xF2,0x33,0xDB,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,
+0x03,0x80,0xCB,0x01,0xA8,0x05,0x74,0x03,0x80,0xCB,0x02,0xA8,0x08,0x74,0x03,0x80,
+0xCB,0x04,0xF6,0x86,0xA7,0x00,0x10,0x74,0x03,0x80,0xCB,0x10,0x8A,0x86,0xA9,0x00,
+0xF6,0xC3,0x04,0x75,0x0A,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04,0x8A,
+0xE0,0x8A,0x86,0xAF,0x00,0xA8,0x80,0x74,0x08,0xF6,0xC4,0x01,0x75,0x03,0x80,0xCB,
+0x20,0xF6,0x86,0xA7,0x00,0x02,0x75,0x0A,0xF7,0x46,0x38,0x04,0x00,0x74,0x03,0x80,
+0xCB,0x40,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0xF3,0xDB,0xF8,
+0xC3,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0xE8,0xDB,0xF8,0xC3,0xAC,0x49,0x3C,0x02,
+0x74,0x37,0x77,0x10,0x84,0xC0,0x74,0x06,0x80,0x4E,0x38,0x01,0xF8,0xC3,0x80,0x66,
+0x38,0xFE,0xF8,0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04,
+0x75,0xEA,0x8A,0x86,0xA5,0x00,0xA8,0x01,0x75,0xE2,0x0C,0x05,0x83,0xC2,0x02,0x88,
+0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0xF8,0xC3,0x81,0x4E,0x38,0x00,0x08,0x8A,0x86,
+0xA5,0x00,0xA8,0x01,0x74,0xC6,0x24,0xFA,0xEB,0xE2,0xAD,0x49,0x49,0xF8,0xC3,0x90,
+0xE8,0x11,0xFA,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0x86,0xDB,0xF8,0xC3,0xB0,0xFF,
+0xE8,0xBF,0xEC,0xF8,0xC3,0x90,0x83,0x66,0x7A,0xFB,0xB0,0x00,0xE8,0x73,0xDB,0xF8,
+0xC3,0x90,0xAC,0x49,0xE8,0x53,0xD9,0x72,0x11,0x36,0x88,0x1E,0x1A,0x01,0x36,0xA0,
+0x8E,0x12,0x0A,0xC3,0x52,0xBA,0x00,0x01,0xEE,0x5A,0xF8,0xC3,0xAC,0x49,0x32,0xE4,
+0x36,0xA3,0x86,0x12,0x05,0x06,0x00,0x36,0x8B,0x1E,0x88,0x12,0x2B,0xD8,0x36,0x89,
+0x1E,0x8A,0x12,0xF8,0xC3,0x90,0xAD,0x8B,0xD8,0xAD,0x83,0xE9,0x04,0x03,0xC3,0x2B,
+0x46,0x76,0x89,0x46,0x78,0xF7,0x46,0x7A,0x02,0x00,0x74,0x0A,0x83,0x66,0x7A,0xFD,
+0xB8,0x00,0x00,0xE8,0x1C,0xDB,0xF8,0xC3,0x06,0x16,0x07,0xAC,0x49,0x25,0x0F,0x00,
+0x6B,0xC0,0x09,0x8D,0xBE,0xFD,0x00,0x03,0xF8,0xAC,0x49,0x25,0x0F,0x00,0xAA,0x85,
+0xC0,0x74,0x08,0x2B,0xC8,0x51,0x8B,0xC8,0xF3,0xA4,0x59,0xE8,0x27,0xF0,0xE8,0x44,
+0x03,0x07,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0xB2,0x13,0x36,0xA3,0xB0,0x13,
+0xF8,0xC3,0x83,0x66,0x7A,0xEF,0xE8,0x2C,0x03,0xF8,0xC3,0x90,0x83,0x4E,0x7A,0x10,
+0xEB,0xF4,0xE8,0x9B,0xF0,0xF8,0xC3,0x90,0xAD,0x3C,0x19,0x77,0x0E,0x3C,0x19,0x77,
+0x0A,0x8B,0xF8,0x81,0xE7,0xFF,0x00,0x88,0xA6,0xC4,0x00,0xF8,0xC3,0x90,0x83,0x4E,
+0x26,0x20,0xAC,0x49,0x32,0xE4,0xD1,0xE0,0x8B,0xD8,0xC1,0xE3,0x02,0x03,0xC3,0x89,
+0x46,0x6E,0x83,0x4E,0x48,0x04,0xB0,0x06,0xE8,0x97,0xDA,0x49,0x46,0xF9,0xC3,0x90,
+0xFE,0x86,0xB3,0x00,0xB0,0x0A,0xE8,0x89,0xDA,0xF8,0xC3,0x90,0x33,0xC0,0xAC,0x49,
+0x6B,0xC0,0x0A,0x89,0x86,0x8A,0x00,0xF8,0xC3,0x90,0xAC,0x49,0x32,0xE4,0x3D,0x0A,
+0x00,0x77,0x05,0xB8,0x0A,0x00,0xEB,0x08,0x3D,0x5A,0x00,0x72,0x03,0xB8,0x5A,0x00,
+0x51,0xF7,0xD8,0x05,0x64,0x00,0x8B,0xC8,0x8B,0x46,0x44,0xF7,0xE1,0xB9,0x64,0x00,
+0xF7,0xF1,0x89,0x46,0x46,0x59,0xF8,0xC3,0xAC,0x49,0xE8,0x85,0xEB,0xF8,0xC3,0x90,
+0xAC,0x49,0x84,0xC0,0x75,0x07,0x81,0x66,0x38,0xFF,0xFD,0xF8,0xC3,0x81,0x4E,0x38,
+0x00,0x02,0xF7,0x46,0x38,0x40,0x00,0x75,0x08,0x8A,0x86,0xA9,0x00,0x88,0x86,0xAA,
+0x00,0xF8,0xC3,0x90,0x51,0x56,0xE8,0x7F,0x0C,0x5E,0x59,0xF8,0xC3,0x90,0xFE,0x86,
+0xB6,0x00,0xB0,0x0A,0xE8,0x0B,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB7,0x00,0xB0,0x0A,
+0xE8,0xFF,0xD9,0xF8,0xC3,0x90,0xFE,0x86,0xB8,0x00,0xB0,0x0A,0xE8,0xF3,0xD9,0xF8,
+0xC3,0x90,0x00,0x90,0x51,0x55,0xAC,0x2E,0xA2,0x52,0x36,0x33,0xC9,0xAD,0x8B,0xF9,
+0xC1,0xE7,0x05,0xA9,0x01,0x00,0x74,0x23,0x2E,0x8B,0xAD,0x44,0x00,0x83,0x7E,0x08,
+0x00,0x74,0x18,0x2E,0x80,0x3E,0x52,0x36,0x01,0x74,0x09,0x60,0xB0,0x04,0xE8,0xBB,
+0x0C,0x61,0xEB,0x07,0x60,0xB0,0xFB,0xE8,0xEC,0x0C,0x61,0x47,0x47,0xD1,0xE8,0x75,
+0xD2,0x41,0x83,0xF9,0x04,0x72,0xC6,0x5D,0x59,0x83,0xE9,0x05,0xF7,0x46,0x38,0x40,
+0x00,0x74,0x05,0xE8,0x87,0xEA,0xF8,0xC3,0xE8,0x8D,0xEA,0xF8,0xC3,0x90,0x36,0xC6,
+0x06,0xC8,0x13,0x01,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0x80,0x12,0xAC,0x49,
+0x36,0x2B,0x06,0x88,0x12,0xF7,0xD8,0x36,0xA3,0x82,0x12,0xF8,0xC3,0x90,0xDE,0x26,
+0xDE,0x26,0xEC,0x26,0xF2,0x26,0xF8,0x26,0xFE,0x26,0x04,0x27,0x0E,0x27,0x16,0x27,
+0x1E,0x27,0x26,0x27,0x2E,0x27,0x34,0x27,0xBE,0x34,0xC6,0x34,0xD2,0x34,0x3A,0x27,
+0x78,0x27,0x80,0x27,0x94,0x27,0xA0,0x27,0xB4,0x27,0xC0,0x27,0xD4,0x27,0xE0,0x27,
+0xF4,0x27,0x00,0x28,0x10,0x28,0xEC,0x34,0xDE,0x26,0x1E,0x28,0x26,0x28,0x2C,0x28,
+0x32,0x28,0x38,0x28,0x4E,0x28,0x8A,0x28,0x06,0x35,0x28,0x35,0x98,0x28,0xBE,0x28,
+0xD2,0x28,0xDE,0x28,0xE6,0x28,0x54,0x35,0x62,0x35,0x6C,0x35,0xEE,0x28,0xC0,0x29,
+0xC8,0x29,0xCE,0x29,0xE0,0x29,0x72,0x35,0x78,0x35,0xF0,0x29,0xFC,0x29,0x8E,0x35,
+0x08,0x2A,0x12,0x2A,0x1C,0x2A,0xB0,0x35,0x36,0x2A,0xBC,0x35,0x5A,0x2A,0x62,0x2A,
+0x68,0x2A,0xCA,0x35,0x7C,0x2A,0xF8,0x35,0x88,0x2A,0xA6,0x2A,0xB8,0x2A,0xCC,0x2A,
+0xDE,0x2A,0xF2,0x2A,0x00,0x36,0x0A,0x2B,0x24,0x2B,0x24,0x36,0x38,0x2B,0x4C,0x2B,
+0x84,0x2B,0x2E,0x36,0x3A,0x36,0x46,0x36,0x54,0x36,0xE8,0x2B,0xAE,0x36,0x40,0x2C,
+0x62,0x2C,0xB6,0x36,0x70,0x28,0xDE,0x26,0xDE,0x26,0xD4,0x2E,0xE8,0x2E,0xF0,0x2E,
+0xF8,0x2E,0x00,0x2F,0x0A,0x2F,0x12,0x2F,0x1A,0x2F,0x22,0x2F,0x2A,0x2F,0x42,0x2F,
+0xBE,0x34,0xC6,0x34,0xD2,0x34,0x50,0x2F,0x8C,0x2F,0x94,0x2F,0xA8,0x2F,0xB4,0x2F,
+0xC8,0x2F,0xD4,0x2F,0xE8,0x2F,0xF4,0x2F,0x08,0x30,0x14,0x30,0x1C,0x30,0xEC,0x34,
+0xDE,0x26,0x24,0x30,0x30,0x30,0x38,0x30,0x44,0x30,0x4C,0x30,0x62,0x30,0xA4,0x30,
+0x06,0x35,0x28,0x35,0xAA,0x30,0xCE,0x30,0xD6,0x30,0xEA,0x30,0xF2,0x30,0x54,0x35,
+0x62,0x35,0x6C,0x35,0xFA,0x30,0xC2,0x31,0xC2,0x31,0xC4,0x31,0xFA,0x31,0x72,0x35,
+0x78,0x35,0x0A,0x32,0x16,0x32,0x8E,0x35,0x22,0x32,0x2C,0x32,0x36,0x32,0xB0,0x35,
+0x4A,0x32,0xBC,0x35,0x74,0x32,0x8C,0x32,0x9A,0x32,0xCA,0x35,0x9E,0x32,0xF8,0x35,
+0xAA,0x32,0xC6,0x32,0xD8,0x32,0xEC,0x32,0xFE,0x32,0x0E,0x33,0x00,0x36,0x12,0x33,
+0x26,0x33,0x24,0x36,0x32,0x33,0x9A,0x33,0xDE,0x33,0x2E,0x36,0x3A,0x36,0x46,0x36,
+0x54,0x36,0x5C,0x34,0xAE,0x36,0xAA,0x34,0xB0,0x34,0xB6,0x36,0x8C,0x30,0xE3,0x28,
+0xF7,0x46,0x38,0x40,0x00,0x75,0x32,0xE8,0xE3,0xE8,0x33,0xC0,0xAC,0x49,0x3D,0x5B,
+0x00,0x77,0x19,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0xCE,0x36,0x72,0x0B,0x85,0xC9,
+0x75,0xE8,0x8B,0x46,0x48,0xE8,0x1A,0x0C,0xC3,0x4E,0x41,0xC3,0x6A,0x00,0x1F,0xC6,
+0x06,0x93,0x12,0x0C,0x9C,0x0E,0xE8,0x63,0xDA,0xE8,0xBC,0xE8,0x33,0xC0,0xAC,0x49,
+0x3D,0x5B,0x00,0x77,0xE7,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0x86,0x37,0x72,0xD9,
+0x85,0xC9,0x75,0xE8,0xC3,0xF7,0x46,0x7A,0x10,0x00,0x75,0x0F,0x83,0xBE,0x84,0x00,
+0x00,0x74,0x08,0xB8,0x48,0x3A,0x89,0x86,0x80,0x00,0xC3,0x81,0xBE,0x80,0x00,0xEC,
+0x3C,0x74,0xF7,0x83,0xBE,0x88,0x00,0x00,0x75,0x05,0xB8,0xEC,0x3C,0xEB,0xE7,0xF7,
+0x46,0x7A,0x08,0x00,0x75,0x40,0x1E,0x60,0x8B,0x8E,0x88,0x00,0x3B,0x4E,0x74,0x77,
+0x33,0x3B,0x4E,0x78,0x77,0x2E,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47,
+0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xF4,0x00,0x8B,0xC1,0xF7,0x46,0x7A,0x01,0x00,0x75,
+0x1D,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xB0,
+0x0C,0xE8,0x3E,0xD7,0x61,0x1F,0xC7,0x86,0x88,0x00,0x00,0x00,0xEB,0xAC,0xE3,0xE3,
+0x50,0x90,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD8,0x90,0x8B,0x8E,0x88,0x00,
+0xE3,0x46,0x8B,0x9E,0x8A,0x00,0x85,0xDB,0x74,0x3E,0xBA,0x50,0xFF,0xED,0x2B,0x86,
+0x82,0x00,0x3B,0xC3,0x72,0x37,0x8D,0xB6,0xF4,0x00,0xC4,0x7E,0x10,0x8B,0xDF,0x26,
+0x03,0x3D,0x47,0x47,0x8B,0xC1,0x16,0x1F,0xF7,0x46,0x7A,0x01,0x00,0x75,0x24,0xF3,
+0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC7,0x86,0x88,
+0x00,0x00,0x00,0xB0,0x0C,0xE8,0xDA,0xD6,0x83,0x66,0x7A,0xF7,0xC3,0xB0,0x00,0xE8,
+0xD0,0xD6,0xC3,0xE3,0xDC,0x50,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD2,0x90,
+0x1E,0x60,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xFD,0x00,0x8B,0x86,0x88,0x00,0x8B,0x96,
+0x84,0x00,0x3A,0x04,0x75,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4,0x00,0xF3,
+0xA6,0x74,0x66,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6,0xFD,0x00,
+0x8B,0x96,0x84,0x00,0x3A,0x04,0x73,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4,
+0x00,0xF3,0xA6,0x74,0x76,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6,
+0xF4,0x00,0xAC,0xF7,0x46,0x7A,0x01,0x00,0x74,0x02,0x24,0x7F,0x1E,0xC5,0x5E,0x10,
+0x8B,0x37,0x88,0x40,0x02,0x46,0x89,0x37,0xFF,0x4E,0x78,0xFF,0x46,0x76,0xFF,0x4E,
+0x74,0x1F,0x8B,0x8E,0x88,0x00,0x49,0x89,0x8E,0x88,0x00,0xE3,0x43,0x8D,0xB6,0xF4,
+0x00,0x8B,0xFE,0x46,0xF3,0xA4,0xE9,0x7D,0xFF,0xC5,0x76,0x10,0x8B,0x1C,0x85,0xDB,
+0x74,0x08,0x03,0xF3,0x83,0xC6,0x03,0x83,0xE6,0xFE,0x8B,0x86,0x84,0x00,0x2B,0xC2,
+0xB4,0x80,0x89,0x04,0x46,0x46,0xC7,0x04,0x00,0x00,0x89,0x76,0x10,0x83,0x4E,0x7A,
+0x04,0xC7,0x86,0x88,0x00,0x00,0x00,0x61,0x1F,0xF9,0xC3,0x33,0xC0,0x61,0x1F,0xC3,
+0xB0,0x80,0x84,0xC0,0x61,0x1F,0xC3,0x90,0x8B,0x4E,0x78,0x2B,0x8E,0x88,0x00,0x76,
+0x27,0x89,0xB6,0x8C,0x00,0x8B,0x5E,0x74,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8,
+0x72,0x02,0x8B,0xC8,0x8B,0xC1,0xE3,0x44,0x33,0xD2,0x8E,0xC2,0x8B,0xD1,0x83,0xBE,
+0x88,0x00,0x00,0x74,0x06,0xE9,0x8E,0x00,0x33,0xC0,0xC3,0x8B,0x5E,0x10,0x03,0x1F,
+0x43,0x43,0x52,0xF7,0x46,0x7A,0x01,0x00,0x75,0x2A,0xAC,0x8D,0xBE,0xE4,0x00,0x8B,
+0x8E,0x86,0x00,0xF2,0xAE,0x74,0x34,0x88,0x07,0x43,0x4A,0x75,0xED,0x58,0x8B,0x5E,
+0x10,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x8B,0xC6,0x2B,0x86,
+0x8C,0x00,0xC3,0x90,0xAC,0x8D,0xBE,0xE4,0x00,0x8B,0x8E,0x86,0x00,0xF2,0xAE,0x74,
+0x0A,0x24,0x7F,0x88,0x07,0x43,0x4A,0x75,0xEB,0xEB,0xD2,0x88,0x86,0xF4,0x00,0xC7,
+0x86,0x88,0x00,0x01,0x00,0x58,0x2B,0xC2,0x74,0x0E,0x8B,0x5E,0x10,0x01,0x07,0x29,
+0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x40,0xE8,0x94,0xFE,0x72,0xBE,0x4A,0x75,
+0x15,0x83,0xBE,0x8A,0x00,0x00,0x74,0xB4,0xBA,0x50,0xFF,0xED,0x89,0x86,0x82,0x00,
+0x83,0x4E,0x7A,0x08,0xEB,0xA6,0x8D,0xBE,0xF4,0x00,0x03,0xBE,0x88,0x00,0xA4,0xFF,
+0x86,0x88,0x00,0xE8,0x6A,0xFE,0x72,0x94,0x79,0x06,0x4A,0x74,0x8F,0xE9,0x5B,0xFF,
+0x4A,0x74,0xCE,0xEB,0xE1,0x90,0x50,0xE8,0x11,0xCC,0x8B,0x46,0x74,0x39,0x46,0x72,
+0x74,0x27,0x1E,0x56,0x51,0x33,0xC9,0xC5,0x76,0x0C,0xAD,0x74,0x10,0x78,0x09,0x03,
+0xC8,0x05,0x01,0x00,0x24,0xFE,0x03,0xF0,0x3B,0x76,0x10,0x76,0xED,0x29,0x4E,0x76,
+0x01,0x4E,0x78,0xE8,0x37,0xCC,0x59,0x5E,0x1F,0x58,0xC3,0x90,0xC4,0x7E,0x10,0x26,
+0x8B,0x1D,0x83,0xC3,0x03,0x26,0x89,0x1D,0x4B,0x03,0xFB,0xAB,0x91,0xAA,0xB8,0x03,
+0x00,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x90,0xC4,0x7E,0x10,0x26,
+0x8B,0x1D,0x43,0x26,0x89,0x1D,0x43,0x03,0xFB,0xAA,0xFF,0x4E,0x78,0xFF,0x46,0x76,
+0xFF,0x4E,0x74,0xC3,0xE8,0xE5,0xFF,0xC3,0x80,0x81,0x84,0x85,0x82,0x83,0x86,0x87,
+0x50,0x53,0x8A,0xDC,0x83,0xE3,0x0E,0xD1,0xEB,0x2E,0x8A,0x87,0x98,0x3B,0x08,0x86,
+0xB0,0x00,0xFE,0x86,0xB1,0x00,0xB0,0x0A,0xE8,0x87,0xD4,0x5B,0x58,0xC3,0x50,0x8A,
+0xC8,0xB8,0xFF,0x00,0xE8,0x95,0xFF,0x58,0xC3,0x90,0x8A,0x86,0xBB,0x00,0xE8,0xAB,
+0xFF,0xC3,0xE8,0xCB,0xFF,0xE8,0xF2,0xFF,0xC3,0x90,0xE8,0xC3,0xFF,0xE8,0xB4,0xFF,
+0xC3,0x90,0x33,0xC0,0xE8,0x95,0xFF,0xC3,0xB8,0xFF,0x00,0x33,0xC9,0xE8,0x6C,0xFF,
+0xC3,0x90,0xB8,0xFF,0x01,0xB1,0x10,0xE8,0x62,0xFF,0xC3,0x90,0xC3,0xFC,0x3B,0xE2,
+0x3B,0xF2,0x3B,0xF2,0x3B,0xFC,0x3B,0xE2,0x3B,0xE8,0x3B,0xE8,0x3B,0xFC,0x3B,0xE2,
+0x3B,0xE8,0x3B,0xE8,0x3B,0xFC,0x3B,0xE2,0x3B,0xE2,0x3B,0xE2,0x3B,0x00,0x10,0x00,
+0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,
+0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x08,0x00,
+0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x51,0x53,0x8B,
+0x4E,0x38,0x81,0xE1,0xFF,0xEE,0xA8,0x04,0x74,0x04,0x81,0xC9,0x00,0x01,0x8A,0xE0,
+0x80,0xE4,0x03,0x24,0x18,0xD0,0xE4,0x0A,0xC4,0x33,0xDB,0x8A,0xD8,0x2E,0x8B,0x87,
+0xFD,0x3B,0x89,0x46,0x7C,0x2E,0x0B,0x8F,0x1D,0x3C,0x89,0x4E,0x38,0xD1,0xEB,0x2E,
+0x8A,0xA7,0x3D,0x3C,0x5B,0x59,0xC3,0xAC,0x49,0x3C,0x01,0x72,0x1D,0x74,0x20,0x3C,
+0x03,0x72,0x23,0x74,0x28,0x3C,0x08,0x72,0x2B,0x74,0x30,0x3C,0x20,0x72,0x37,0x74,
+0x3A,0xBB,0xDA,0x3B,0x32,0xE4,0x89,0x5E,0x7E,0xC3,0xBB,0xA0,0x3B,0xEB,0xF5,0xBB,
+0x94,0x3B,0xB4,0x01,0xEB,0xF0,0xBB,0xFC,0x3B,0xB4,0x02,0xEB,0xE9,0xBB,0xE2,0x3B,
+0xB4,0x03,0xEB,0xE2,0xBB,0xBE,0x3B,0xB4,0x04,0xEB,0xDB,0xBB,0xCA,0x3B,0xAC,0x49,
+0x88,0x86,0xBB,0x00,0xEB,0xCE,0xBB,0xD2,0x3B,0xEB,0xF3,0xBB,0xFC,0x3B,0xEB,0xC4,
+0xA9,0x04,0x00,0x75,0xD1,0xA9,0x08,0x00,0x75,0xDA,0xEB,0xD1,0x8B,0x5E,0x74,0x8B,
+0x4E,0x78,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8,0x72,0x02,0x8B,0xC8,0x8B,0xC1,
+0xE3,0x2C,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47,0xF7,0x46,0x7A,0x01,
+0x00,0x75,0x1C,0xF7,0xC7,0x01,0x00,0x74,0x02,0x49,0xA4,0xD1,0xE9,0xF3,0xA5,0x73,
+0x01,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x50,
+0x53,0xBB,0x7F,0x7F,0xF7,0xC7,0x01,0x00,0x74,0x05,0x49,0xAC,0x22,0xC3,0xAA,0xD1,
+0xE9,0xE3,0x1D,0x9C,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x14,0xAD,0x23,0xC3,0xAB,0x49,
+0x74,0x0D,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x06,0xAD,0x23,0xC3,0xAB,0xE2,0xE5,0x9D,
+0x73,0x04,0xAC,0x22,0xC3,0xAB,0x5B,0x58,0xEB,0xB8,0xE8,0xCE,0xC9,0x8B,0x5E,0x38,
+0xF7,0xC3,0x10,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x40,0x00,0x74,0x05,0xE8,0xB8,0xE3,
+0xEB,0x03,0xE8,0xA8,0xE3,0x81,0x66,0x38,0xEF,0xFB,0xF6,0xC3,0x10,0x74,0x3C,0xF6,
+0xC3,0x02,0x74,0x06,0xE4,0xD8,0x0C,0x01,0xE6,0xD8,0xF6,0xC3,0x04,0x74,0x11,0x83,
+0xC2,0x08,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x08,
+0xF6,0xC3,0x08,0x74,0x0F,0xE8,0x8B,0xE3,0x72,0x0A,0x8A,0x86,0xC0,0x00,0xE6,0x38,
+0xB0,0x23,0xE6,0x0A,0xF7,0xC3,0x00,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x00,0x08,0x75,
+0xF9,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0x40,0x75,0x0D,0xA8,0x10,0x75,0xEC,0x0C,0x10,
+0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x01,0x75,0xDF,0x83,0xC2,0x02,0x0C,0x05,
+0xEE,0x88,0x86,0xA5,0x00,0xC3,0xB0,0x00,0xE8,0x47,0xD2,0xEB,0x0F,0xB0,0x02,0xE8,
+0x90,0x0E,0xEB,0x08,0x83,0x66,0x38,0xDF,0x83,0x4E,0x7A,0x02,0x33,0xC0,0x8E,0xD8,
+0xFA,0xA0,0x92,0x12,0x40,0xA2,0x92,0x12,0x3C,0x05,0x72,0x1E,0xC6,0x06,0x92,0x12,
+0x00,0xFB,0xB0,0x01,0xE8,0x6B,0x0E,0xFA,0xA1,0x26,0x01,0x23,0x06,0x2A,0x01,0xA8,
+0x01,0x75,0x07,0xE8,0xE2,0x07,0xE8,0x61,0x09,0x90,0xB0,0x00,0xE8,0x37,0xD2,0xFB,
+0x85,0xED,0x74,0xB9,0xFA,0xF7,0x46,0x7A,0x46,0x00,0x75,0xC0,0x8B,0x46,0x78,0x3D,
+0x0A,0x00,0x72,0xB0,0x8B,0x4E,0x74,0x83,0xF9,0x50,0x72,0x9A,0x83,0x66,0x38,0xDF,
+0xC5,0x76,0x14,0x8B,0x46,0x3A,0x85,0xC0,0x75,0x58,0xAD,0x85,0xC0,0x75,0x0F,0xE8,
+0xF8,0xFE,0xF7,0x46,0x7A,0x08,0x00,0x74,0x93,0xE8,0xA0,0xFA,0xEB,0x8E,0x3B,0x76,
+0x04,0x76,0x21,0xB9,0x02,0x00,0x39,0x4E,0x2E,0x77,0x05,0xC7,0x46,0x2E,0x00,0x00,
+0x56,0x8B,0x76,0x2C,0x89,0x76,0x04,0xC7,0x04,0x00,0x00,0x46,0x46,0x89,0x76,0x2C,
+0x29,0x4E,0x2E,0x5E,0x85,0xC0,0x79,0x17,0xF6,0xC4,0x10,0x74,0x05,0xFF,0x56,0x7C,
+0xEB,0x03,0xFF,0x56,0x7E,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x85,0xD1,0xEB,0x86,0x89,
+0x46,0x3A,0xFF,0x96,0x80,0x00,0x29,0x46,0x3A,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x71,
+0xD1,0xE9,0x71,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x10,0x02,
+0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
-0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
-0xC0,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,
+0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
@@ -1021,860 +1023,860 @@
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-0x80,0x80,0x80,0x80,0x80,0x80,0x30,0x41,0x5A,0x41,0xB2,0x41,0xD6,0x41,0xE8,0x41,
-0xFA,0x41,0xC3,0x90,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x80,0x66,0x27,
-0xFD,0x8B,0x56,0x24,0x83,0xFA,0x04,0x72,0xE9,0x83,0xEA,0x02,0x8B,0xD9,0x3B,0xCA,
-0x76,0x02,0x8B,0xCA,0xB0,0x0A,0x57,0x51,0x8B,0xFE,0xF2,0xAE,0x8B,0xC1,0x59,0x5F,
-0x75,0x1E,0x50,0x40,0x2B,0xC8,0x74,0x06,0x2B,0xD1,0x2B,0xD9,0xF3,0xA4,0x59,0x4B,
-0x4A,0x4A,0xB0,0x0D,0xAA,0xA4,0x3B,0xCA,0x76,0x02,0x8B,0xCA,0xE3,0x13,0xEB,0xD4,
-0x2B,0xD9,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3,0xA5,0x73,0x01,
-0xA4,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x29,0x7E,0x24,0x01,0x7E,0x1A,0x8B,0xCB,0x80,
-0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0x18,0x03,
-0x61,0xC3,0xC3,0x90,0xE8,0x7C,0x02,0x72,0xF9,0x90,0x83,0x4E,0x26,0x20,0x8B,0x46,
-0x6A,0x89,0x46,0x6E,0x8B,0x46,0x48,0x0D,0x04,0x00,0x25,0xBF,0xFF,0x89,0x46,0x48,
-0xB0,0x06,0xE8,0xD9,0xCF,0xC3,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29,
-0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x05,0x83,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,
-0xE8,0xD5,0x02,0x61,0xC3,0x90,0x8A,0xBE,0xC2,0x00,0xEB,0x24,0xF7,0x46,0x48,0x40,
-0x00,0x75,0xB1,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x8B,0x56,0x24,0x83,
-0xEA,0x0A,0x78,0x9E,0x03,0xD7,0x80,0x66,0x27,0xFD,0x33,0xC0,0x8A,0xBE,0xC2,0x00,
-0xE3,0xB4,0x3B,0xFA,0x77,0xB0,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xB6,0x3E,0x93,0x22,
-0xDF,0x75,0x17,0xAA,0xE3,0xA0,0x3B,0xFA,0x77,0x9C,0xAC,0x49,0x93,0x2E,0x8A,0x87,
-0xB6,0x3E,0x93,0x22,0xDF,0x75,0x03,0xAA,0xEB,0xD6,0xF6,0xC3,0x7F,0x75,0x05,0xFF,
-0x46,0x66,0xEB,0xDF,0xF6,0xC3,0x40,0x75,0x0C,0x8B,0xD8,0x83,0xEB,0x08,0xD1,0xE3,
-0x2E,0xFF,0xA7,0xB6,0x3F,0xFF,0x46,0x66,0x2C,0x20,0xEB,0xC7,0x85,0xC0,0x74,0x2C,
-0x89,0x46,0x6A,0x83,0x4E,0x48,0x40,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,
-0x29,0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x08,0x83,0x66,0x26,0xFD,0xE8,0xA3,0x01,
-0xC3,0x60,0xB0,0xFD,0xE8,0x31,0x02,0x61,0xE8,0x98,0x01,0xC3,0xE9,0x57,0xFF,0x90,
-0x8B,0x5E,0x66,0x4B,0x78,0x03,0x89,0x5E,0x66,0xAA,0x8B,0x5E,0x64,0xF7,0xC3,0x00,
-0x20,0x75,0x03,0xE9,0x40,0xFF,0xF7,0xC3,0x40,0x00,0x74,0x08,0x8A,0x86,0xC1,0x00,
-0xAA,0xE9,0x32,0xFF,0xB8,0x32,0x00,0xEB,0xA3,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,
-0x83,0xC3,0x08,0x80,0xE3,0xF8,0x89,0x5E,0x66,0x8B,0x5E,0x64,0x81,0xE3,0x00,0x18,
-0x81,0xFB,0x00,0x18,0x74,0x2D,0xAA,0x85,0xDB,0x74,0x25,0xF7,0x46,0x64,0x40,0x00,
-0x75,0x18,0x81,0xFB,0x00,0x10,0x74,0x0C,0x8B,0x46,0x66,0x2B,0x46,0x68,0xC1,0xE0,
-0x04,0xE9,0x68,0xFF,0xB8,0x64,0x00,0xE9,0x62,0xFF,0x8A,0x86,0xC1,0x00,0xAA,0xAA,
-0xE9,0xE3,0xFE,0x51,0x8B,0x4E,0x66,0x2B,0x4E,0x68,0xB0,0x20,0xF3,0xAA,0x59,0xE9,
-0xD4,0xFE,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x8B,0x5E,0x64,0xF7,0xC3,0x24,0x00,0x74,
-0x10,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x04,0x00,0x74,0x05,0xB0,0x0D,0xAA,0xB0,
-0x0A,0xAA,0xEB,0x48,0x90,0x90,0xAA,0xF7,0x46,0x64,0x00,0x40,0x74,0x06,0xB8,0xD0,
-0x07,0xE9,0x18,0xFF,0xE9,0x9F,0xFE,0x90,0xAA,0xF7,0x46,0x64,0x00,0x80,0x74,0x06,
-0xB8,0xD0,0x07,0xE9,0x06,0xFF,0xE9,0x8D,0xFE,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,
-0x85,0xDB,0x75,0x0C,0x8B,0x5E,0x64,0xF7,0xC3,0x10,0x00,0x74,0x06,0xE9,0x76,0xFE,
-0x8B,0x5E,0x64,0xF7,0xC3,0x08,0x00,0x74,0x27,0xB0,0x0A,0xAA,0xF7,0xC3,0x20,0x00,
-0x75,0x1F,0xF7,0xC3,0x00,0x01,0x75,0x03,0xE9,0x5B,0xFE,0xF7,0xC3,0x40,0x00,0x75,
-0x06,0xB8,0x64,0x00,0xE9,0xC5,0xFE,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0x46,0xFE,
-0xAA,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x00,0x06,0x74,0xF1,0xF7,0xC3,0x40,0x00,
-0x74,0x19,0x8A,0x86,0xC1,0x00,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00,0x04,0x72,0x06,
-0x76,0x02,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xE9,0x1B,0xFE,0x81,0xE3,0x00,0x06,0x81,
-0xFB,0x00,0x04,0x72,0x0E,0x76,0x06,0xB8,0x96,0x00,0xE9,0x7F,0xFE,0xB8,0x64,0x00,
-0xE9,0x79,0xFE,0x8B,0x46,0x68,0xE9,0x73,0xFE,0x90,0x36,0x8B,0x0E,0xDA,0x12,0x83,
-0xF9,0x32,0x73,0x1D,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8D,0x76,0x4C,0xBF,
-0xDC,0x12,0x03,0xF9,0xA5,0xA5,0xA5,0x83,0xC1,0x06,0x89,0x0E,0xDA,0x12,0x07,0x1F,
-0xC3,0xB0,0x08,0xE8,0x88,0xCD,0xC3,0x90,0x83,0x66,0x48,0xFE,0xE8,0xAD,0xC4,0xE8,
-0xC8,0xFF,0xC3,0xF6,0x46,0x27,0x02,0x75,0x0F,0x9C,0xFA,0x83,0x7E,0x1A,0x00,0x74,
-0x09,0x80,0x4E,0x27,0x01,0x9D,0xF9,0xC3,0xF8,0xC3,0x50,0x52,0xF7,0x46,0x38,0x40,
-0x00,0x74,0x1D,0xE8,0x4E,0xDE,0x83,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x27,0x83,0xEA,
-0x08,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x5A,0x58,0xEB,0xD1,
-0xE8,0x26,0xDE,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,
-0x0C,0x5A,0x58,0xEB,0xBC,0x80,0x4E,0x27,0x02,0x5A,0x58,0x9D,0xF8,0xC3,0x08,0x46,
-0x26,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00,0x75,0x14,0xF6,0xC1,
-0x06,0x74,0x23,0xE8,0xF3,0xDD,0x8A,0xC1,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,
-0x9D,0xC3,0xF6,0xC1,0x02,0x74,0x0F,0xE8,0xEA,0xDD,0x83,0xC2,0x02,0x8A,0xC1,0x24,
-0xFD,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x8B,0x5E,0x26,0x22,0xC3,0x88,0x46,0x26,
-0x74,0x01,0xC3,0x80,0x66,0x27,0xFD,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,
-0x40,0x00,0x75,0x16,0xF6,0xC1,0x04,0x75,0x0F,0xE8,0xAD,0xDD,0x8A,0xC1,0x24,0xFD,
-0x0C,0x04,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3,0xF6,0xC1,0x02,0x75,0xF9,0xE8,
-0xA2,0xDD,0x83,0xC2,0x0A,0xEC,0xA8,0x20,0x75,0x0E,0x83,0xEA,0x08,0x8A,0xC1,0x0C,
-0x02,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x83,0xEA,0x0A,0x33,0xC9,0x8A,0x4E,0x1C,
-0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1B,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0x1E,
-0xC5,0x76,0x00,0xF3,0x6E,0x1F,0x89,0x76,0x00,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,
-0xEB,0xCD,0x85,0xC0,0x74,0x12,0x01,0x46,0x2A,0x8B,0xC8,0x1E,0xC5,0x76,0x00,0xF3,
-0x6E,0x1F,0x89,0x76,0x00,0x89,0x4E,0x1A,0xF6,0xC7,0x01,0x75,0x23,0x80,0xCB,0x02,
-0x89,0x5E,0x26,0xE8,0x22,0xC3,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,
-0x88,0x86,0xA5,0x00,0xF6,0xC7,0x10,0x75,0x05,0xB0,0x02,0xE8,0x30,0xCC,0x9D,0xC3,
-0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0xEB,0x86,0x90,0x8B,0xD1,0x8B,0x46,0x24,0x3B,
-0xC8,0x76,0x02,0x8B,0xC8,0x2B,0xD1,0x2B,0xC1,0x8B,0xD9,0xE3,0x22,0x80,0x66,0x27,
-0xFD,0x8E,0x46,0x02,0x8B,0x7E,0x22,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,
-0xE9,0xF3,0xA5,0x73,0x01,0xA4,0x89,0x7E,0x22,0x89,0x46,0x24,0x01,0x5E,0x1A,0x8B,
-0xCA,0x80,0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,
-0xF6,0xFE,0x61,0xC3,0x50,0xE4,0x0A,0x84,0xC0,0x75,0x0A,0x86,0x86,0xA1,0x00,0x84,
-0xC0,0x74,0x0A,0xE6,0x0A,0x58,0x0C,0x20,0x89,0x46,0x48,0xF9,0xC3,0x58,0x24,0xDF,
-0x89,0x46,0x48,0xF8,0xC3,0x90,0xFB,0xB0,0x02,0xE8,0xE8,0x07,0xFA,0xE8,0x2E,0x01,
-0xFB,0xB0,0x01,0xE8,0xDE,0x07,0xFA,0xB0,0x02,0xE8,0xD6,0xCB,0xFB,0x85,0xED,0x74,
-0xE5,0xFA,0x8E,0x5E,0x0A,0xFB,0x90,0xFA,0x8B,0x46,0x48,0x8B,0x76,0x40,0xA8,0x8C,
-0x75,0xDE,0xA8,0x20,0x74,0x1A,0x50,0xE8,0x6F,0xDC,0x58,0xE8,0xA6,0xFF,0x73,0x10,
-0xB0,0x02,0xE8,0x79,0xCB,0xEB,0xC9,0x90,0x25,0xFF,0x00,0x8B,0xC8,0xEB,0x36,0x90,
-0xA8,0x01,0x75,0x22,0x46,0x83,0xE6,0xFE,0x3B,0x76,0x08,0x74,0x79,0xAD,0x8A,0xFC,
-0xB3,0xF0,0x22,0xFB,0x3A,0xFB,0x74,0xE0,0x3A,0xBE,0xA0,0x00,0x74,0x2E,0xE8,0xD2,
-0xFD,0x73,0x77,0xEB,0x9B,0x90,0x8A,0xE0,0x24,0xFC,0x88,0x46,0x48,0x8B,0x4E,0x4A,
-0xF6,0xC4,0x02,0x74,0x1D,0xE8,0xBB,0xFD,0x72,0x86,0xE8,0x13,0xF3,0x89,0x76,0x40,
-0xE3,0x93,0x83,0x4E,0x48,0x03,0x89,0x4E,0x4A,0xE9,0x74,0xFF,0x25,0xFF,0x0F,0x8B,
-0xC8,0x90,0x8B,0x86,0x98,0x00,0x85,0xC0,0x74,0x1A,0x51,0x8A,0x8E,0xA0,0x00,0xC0,
-0xE9,0x04,0xBA,0x01,0x00,0xD3,0xE2,0x59,0x23,0xC2,0x74,0x08,0x03,0xF1,0x89,0x76,
-0x40,0xE9,0x61,0xFF,0xFF,0x56,0x62,0xE3,0xF5,0x83,0x4E,0x48,0x01,0x89,0x4E,0x4A,
-0x89,0x76,0x40,0xE9,0x3A,0xFF,0x81,0x4E,0x26,0x00,0x10,0x8B,0x46,0x50,0x3B,0x46,
-0x46,0x77,0x03,0xE8,0x52,0xFD,0xE9,0x27,0xFF,0x90,0x88,0xBE,0xA0,0x00,0xEB,0xAC,
-0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xB0,0x04,0xEE,0xEC,0x84,0xC0,0x75,
-0x12,0xB0,0x04,0xEE,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0x06,0xC7,0x06,0x84,
-0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,
-0x01,0xEC,0xA8,0x01,0x75,0xED,0xBA,0x08,0x01,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,
-0x74,0xE1,0xC7,0x06,0x84,0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x90,0x36,0xF7,
-0x06,0x24,0x01,0x01,0x00,0x75,0x30,0x36,0x8B,0x0E,0xDA,0x12,0x80,0xF9,0x36,0x73,
-0x26,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0xDC,0x12,0x03,0xF9,0xB0,0x08,0xE8,0x91,
-0xCA,0x85,0xED,0x74,0x0E,0x8D,0x76,0x4C,0xA5,0xA5,0xA5,0x80,0xC1,0x06,0x80,0xF9,
-0x36,0x72,0xE9,0x89,0x0E,0xDA,0x12,0xC3,0xC3,0x90,0xF7,0x06,0x26,0x01,0x01,0x00,
-0x75,0xF6,0x8B,0x0E,0x20,0x13,0x85,0xC9,0x75,0xEE,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,
-0xBF,0x24,0x13,0xB9,0x36,0x00,0xB0,0x0A,0xE8,0x57,0xCA,0x85,0xED,0x75,0x06,0xE9,
-0x12,0x01,0xE9,0x0A,0x01,0x33,0xDB,0x8A,0x46,0x4C,0x8A,0xA6,0xB3,0x00,0xFE,0xCC,
-0x78,0x0E,0x88,0xA6,0xB3,0x00,0x0A,0xDC,0xB4,0x0A,0xAB,0x83,0xE9,0x02,0x76,0xE2,
-0x8A,0xA6,0xB2,0x00,0xFE,0xCC,0x78,0x0E,0x88,0xA6,0xB2,0x00,0x0A,0xDC,0xB4,0x08,
-0xAB,0x83,0xE9,0x02,0x76,0xCC,0x8A,0xA6,0xB1,0x00,0xFE,0xCC,0x78,0x18,0x8A,0xBE,
-0xB0,0x00,0x75,0x04,0x88,0xA6,0xB0,0x00,0x88,0xA6,0xB1,0x00,0x0A,0xDC,0x8A,0xE7,
-0xAB,0x83,0xE9,0x02,0x76,0xAC,0x8A,0xA6,0xB4,0x00,0xFE,0xCC,0x78,0x1F,0x88,0xA6,
-0xB4,0x00,0x0A,0xDC,0xB4,0x0B,0xAB,0x8A,0x86,0xBC,0x00,0x8A,0xA6,0xBD,0x00,0xAB,
-0x8B,0x86,0xBE,0x00,0xAB,0x83,0xE9,0x06,0x76,0x88,0x8A,0x46,0x4C,0x8A,0xA6,0xB6,
-0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB6,0x00,0x0A,0xDC,0xB4,0x0C,0xAB,0xE8,0xF5,
-0xCB,0xAB,0x8B,0x46,0x2A,0xAB,0x83,0xE9,0x06,0x76,0x74,0x8A,0x46,0x4C,0x8A,0xA6,
-0xB7,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB7,0x00,0x0A,0xDC,0xB4,0x0D,0xAB,0xE8,
-0xD4,0xCB,0xAB,0x8B,0x46,0x34,0xAB,0x83,0xE9,0x06,0x76,0x53,0x8A,0x46,0x4C,0x8A,
-0xA6,0xB8,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB8,0x00,0x0A,0xDC,0xB4,0x0E,0xAB,
-0xA1,0x50,0x12,0xAB,0xA1,0x52,0x12,0xAB,0x83,0xE9,0x06,0x76,0x32,0x8A,0x46,0x4C,
-0x8A,0xA6,0xB5,0x00,0xFE,0xCC,0x78,0x18,0x88,0xA6,0xB5,0x00,0x0A,0xDC,0xB4,0x0F,
-0xAB,0x8B,0x86,0x9A,0x00,0xAB,0x8B,0x86,0x9C,0x00,0xAB,0x83,0xE9,0x06,0x76,0x0F,
-0x84,0xDB,0x75,0x03,0xE9,0xEF,0xFE,0xB0,0x0A,0xE8,0x12,0xC9,0xE9,0xE7,0xFE,0xB0,
-0x0A,0xE8,0x0A,0xC9,0xF7,0xD9,0x83,0xC1,0x36,0x8B,0xC1,0x0D,0x80,0x00,0x86,0xC4,
-0xA3,0x22,0x13,0x41,0x41,0x89,0x0E,0x20,0x13,0xC3,0xA1,0x84,0x12,0x2B,0xC1,0x72,
-0x11,0xA3,0x84,0x12,0xBE,0x22,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x20,0x13,
-0xF8,0xC3,0xF9,0xC3,0xC3,0x81,0xEF,0x6A,0x13,0x74,0xF9,0x8B,0xC7,0x0D,0x80,0x00,
-0x86,0xC4,0xA3,0x68,0x13,0x47,0x47,0x89,0x3E,0x66,0x13,0xC3,0xF7,0x06,0x2A,0x01,
-0x01,0x00,0x75,0xE0,0x8B,0x0E,0x66,0x13,0xE3,0x07,0x80,0xF9,0x20,0x77,0xD5,0x49,
-0x49,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x6A,0x13,0x8B,0xF7,0x03,0xF9,0x83,0xC6,
-0x34,0x3B,0xFE,0x77,0xC0,0xB0,0x0E,0xE8,0xC8,0xC8,0x85,0xED,0x74,0xB7,0x8A,0x46,
-0x4C,0x8A,0xB6,0xB9,0x00,0xFE,0xCE,0x78,0x15,0x88,0xB6,0xB9,0x00,0x8A,0xA6,0xA9,
-0x00,0x80,0xCC,0xC0,0xAB,0x84,0xF6,0x74,0x05,0xB0,0x0E,0xE8,0x70,0xC8,0x8A,0xB6,
-0xBA,0x00,0xFE,0xCE,0x78,0xCB,0x8A,0x9E,0xA9,0x00,0x8A,0xBE,0xAB,0x00,0x8A,0x56,
-0x3F,0x8A,0xF3,0x32,0xF7,0x0A,0xB6,0xAC,0x00,0xC6,0x86,0xAC,0x00,0x00,0x22,0xF2,
-0x74,0x4B,0xF6,0xC6,0x08,0x74,0x0F,0xB4,0x02,0xF6,0xC3,0x08,0x75,0x02,0xB4,0x03,
-0xAB,0x80,0xE6,0xF7,0x74,0x37,0xF6,0xC6,0x01,0x74,0x0F,0xB4,0x00,0xF6,0xC3,0x01,
-0x75,0x02,0xB4,0x01,0xAB,0x80,0xE6,0xFE,0x74,0x23,0xF6,0xC6,0x02,0x74,0x0F,0xB4,
-0x04,0xF6,0xC3,0x02,0x75,0x02,0xB4,0x05,0xAB,0x80,0xE6,0xFD,0x74,0x0F,0xF6,0xC6,
-0x04,0x74,0x0A,0xB4,0x06,0xF6,0xC3,0x04,0x75,0x02,0xB4,0x07,0xAB,0xC6,0x86,0xBA,
-0x00,0x00,0x88,0x9E,0xAB,0x00,0xE9,0x58,0xFF,0x90,0xA1,0x84,0x12,0x2B,0xC1,0x72,
-0x11,0xA3,0x84,0x12,0xBE,0x68,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x66,0x13,
-0xF8,0xC3,0xF9,0xC3,0xA1,0x84,0x12,0x41,0x41,0x2B,0xC1,0x72,0x23,0xA3,0x84,0x12,
-0x8B,0xC1,0x48,0x48,0x32,0xE4,0x0C,0x80,0x86,0xC4,0xEF,0x90,0x90,0x90,0x90,0x90,
-0xBE,0xDC,0x12,0x49,0x49,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0xDA,0x12,0xF8,0xC3,
-0xF9,0xC3,0x8A,0xC8,0x8A,0x46,0x4C,0xB4,0x01,0x83,0xEB,0x06,0xEF,0x90,0x90,0x90,
-0x90,0x90,0xB8,0x01,0x00,0xEF,0x90,0x90,0x90,0x90,0x90,0x8A,0xC1,0xEF,0x90,0x90,
-0x90,0x90,0x90,0xE9,0x97,0x00,0xE9,0xAC,0x00,0x33,0xC0,0x8E,0xD8,0x89,0x1E,0x84,
-0x12,0xC3,0x36,0x8B,0x1E,0x84,0x12,0xFB,0x90,0xFA,0xB0,0x0C,0xE8,0xA3,0xC7,0x85,
-0xED,0x74,0xE6,0xC5,0x76,0x0C,0x83,0xFB,0x14,0x72,0xDB,0xFB,0x90,0xFA,0xAD,0x85,
-0xC0,0x78,0xAF,0x74,0xE2,0x8B,0xFE,0x03,0xF8,0x36,0x8B,0x0E,0x86,0x12,0x3B,0xC1,
-0x77,0x02,0x8B,0xC8,0x83,0xEB,0x04,0x3B,0xD9,0x77,0x02,0x8B,0xCB,0x33,0xC0,0x8A,
-0x46,0x4C,0xEF,0x90,0x90,0x90,0x90,0x90,0x8B,0xC1,0xEF,0x90,0x90,0x90,0x90,0x90,
-0x41,0x80,0xE1,0xFE,0x2B,0xD9,0x51,0xD1,0xE9,0xF3,0x6F,0x90,0x59,0x8B,0xC7,0x40,
-0x24,0xFE,0x3B,0xC6,0x74,0x27,0x2B,0xFE,0x4E,0x4E,0x53,0x8B,0x5E,0x10,0x3B,0xF3,
-0x72,0x13,0x03,0x1F,0x83,0xC3,0x03,0x80,0xE3,0xFE,0xC7,0x07,0x00,0x00,0x83,0x6E,
-0x74,0x02,0x89,0x5E,0x10,0x5B,0x89,0x3C,0x89,0x76,0x0C,0xEB,0x89,0x89,0x76,0x0C,
-0x39,0x76,0x10,0x77,0x81,0x72,0x08,0x83,0x3C,0x00,0x74,0x03,0xE9,0x77,0xFF,0xE8,
-0x27,0xBE,0xE9,0x62,0xFF,0x36,0x89,0x1E,0x84,0x12,0xB0,0x0C,0xE8,0xCF,0xC6,0x33,
-0xC0,0x8E,0xD8,0xC3,0xA1,0x84,0x12,0x3D,0x10,0x00,0x72,0x77,0xBA,0x04,0x01,0x3B,
-0x06,0x88,0x12,0x75,0x06,0xC7,0x06,0x7E,0x12,0x00,0x00,0x8B,0x0E,0xDA,0x12,0xE3,
-0x0B,0xE8,0xD0,0xFE,0x72,0x57,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x20,0x13,
-0xE3,0x0B,0xE8,0xA5,0xFD,0x72,0x46,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x66,
-0x13,0xE3,0x0B,0xE8,0x94,0xFE,0x72,0x35,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0xA1,0x28,
-0x01,0xA9,0x01,0x00,0x75,0x03,0xE8,0xF9,0xFE,0x80,0x3E,0x8D,0x12,0x00,0x75,0x1D,
-0xA1,0x84,0x12,0x3D,0x20,0x00,0x76,0x15,0x3B,0x06,0x82,0x12,0x76,0x09,0xA1,0x7E,
-0x12,0x3B,0x06,0x80,0x12,0x72,0x0C,0x80,0x0E,0x90,0x12,0x80,0xC3,0xB0,0x80,0xFF,
-0x16,0x7C,0x12,0xC3,0x80,0x0E,0x90,0x12,0x40,0xC3,0x6A,0x00,0x1F,0xC6,0x06,0x93,
-0x12,0x17,0x9C,0x0E,0xE8,0xD1,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x20,0x9C,
-0x0E,0xE8,0xC4,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x16,0x9C,0x0E,0xE8,0xB7,
-0xC8,0x90,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xCA,0xFB,0x90,0xFA,0xBA,0x04,0x01,
-0xED,0x90,0x90,0x90,0x90,0x90,0x3A,0x06,0x94,0x12,0x77,0xBE,0x33,0xDB,0x8A,0xD8,
-0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0xC4,0x7E,0x08,0x85,0xFF,0x74,0xB9,0xF6,0xC4,
-0xC0,0x75,0x55,0x32,0xC0,0xC1,0xE0,0x02,0x80,0xE4,0xF0,0x8B,0xF0,0xED,0x90,0x90,
-0x90,0x90,0x90,0x85,0xC0,0x74,0xBB,0x8B,0xC8,0x41,0x80,0xE1,0xFE,0x0B,0xC6,0x8B,
-0x5E,0x50,0x4B,0x4B,0x2B,0xD9,0x78,0x9C,0xAB,0x8B,0xC1,0x40,0x40,0x01,0x46,0x4E,
-0xD1,0xE9,0xF3,0x6D,0x90,0x89,0x5E,0x50,0x89,0x7E,0x08,0x8B,0x46,0x26,0x80,0xE4,
-0xEF,0x89,0x46,0x26,0xF6,0xC4,0x01,0x75,0x0C,0xF7,0x46,0x48,0x0C,0x00,0x75,0x05,
-0xB0,0x02,0xE8,0x99,0xC5,0xE9,0x7A,0xFF,0x86,0xC4,0x8B,0xC8,0x83,0xE1,0x3F,0x41,
-0x80,0xE1,0xFE,0xE3,0x0A,0x3C,0x80,0x72,0x09,0x24,0x3F,0xB4,0xF0,0xEB,0xB0,0xE9,
-0x60,0xFF,0x25,0x3F,0x00,0x33,0xFF,0x8E,0xC7,0xBF,0x96,0x12,0x8B,0xF7,0xD1,0xE9,
-0xF3,0x6D,0x90,0x8B,0xC8,0xE8,0x48,0xED,0xE9,0x47,0xFF,0x90,0x6A,0x00,0x1F,0xC6,
-0x06,0x93,0x12,0x1B,0x9C,0x0E,0xE8,0xEF,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,
-0xD8,0x8E,0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xB0,0x06,0xEE,0xEC,0xA2,
-0x8C,0x12,0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,
-0x00,0xE8,0x60,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0x04,0xFF,0xB8,0x00,
-0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93,
-0x12,0x1B,0x9C,0x0E,0xE8,0xA1,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,
-0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xBA,0x08,0x01,0xEC,0xA2,0x8C,0x12,
+0x80,0x80,0x80,0x80,0x4E,0x41,0x78,0x41,0xD0,0x41,0xF4,0x41,0x06,0x42,0x18,0x42,
+0xC3,0x90,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x80,0x66,0x27,0xFD,0x8B,
+0x56,0x24,0x83,0xFA,0x04,0x72,0xE9,0x83,0xEA,0x02,0x8B,0xD9,0x3B,0xCA,0x76,0x02,
+0x8B,0xCA,0xB0,0x0A,0x57,0x51,0x8B,0xFE,0xF2,0xAE,0x8B,0xC1,0x59,0x5F,0x75,0x1E,
+0x50,0x40,0x2B,0xC8,0x74,0x06,0x2B,0xD1,0x2B,0xD9,0xF3,0xA4,0x59,0x4B,0x4A,0x4A,
+0xB0,0x0D,0xAA,0xA4,0x3B,0xCA,0x76,0x02,0x8B,0xCA,0xE3,0x13,0xEB,0xD4,0x2B,0xD9,
+0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3,0xA5,0x73,0x01,0xA4,0x89,
+0x7E,0x22,0x2B,0x7E,0x6C,0x29,0x7E,0x24,0x01,0x7E,0x1A,0x8B,0xCB,0x80,0x7E,0x26,
+0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0x18,0x03,0x61,0xC3,
+0xC3,0x90,0xE8,0x7C,0x02,0x72,0xF9,0x90,0x83,0x4E,0x26,0x20,0x8B,0x46,0x6A,0x89,
+0x46,0x6E,0x8B,0x46,0x48,0x0D,0x04,0x00,0x25,0xBF,0xFF,0x89,0x46,0x48,0xB0,0x06,
+0xE8,0xBF,0xCF,0xC3,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29,0x7E,0x24,
+0x80,0x7E,0x26,0x02,0x74,0x05,0x83,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0xD5,
+0x02,0x61,0xC3,0x90,0x8A,0xBE,0xC2,0x00,0xEB,0x24,0xF7,0x46,0x48,0x40,0x00,0x75,
+0xB1,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x8B,0x56,0x24,0x83,0xEA,0x0A,
+0x78,0x9E,0x03,0xD7,0x80,0x66,0x27,0xFD,0x33,0xC0,0x8A,0xBE,0xC2,0x00,0xE3,0xB4,
+0x3B,0xFA,0x77,0xB0,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xD4,0x3E,0x93,0x22,0xDF,0x75,
+0x17,0xAA,0xE3,0xA0,0x3B,0xFA,0x77,0x9C,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xD4,0x3E,
+0x93,0x22,0xDF,0x75,0x03,0xAA,0xEB,0xD6,0xF6,0xC3,0x7F,0x75,0x05,0xFF,0x46,0x66,
+0xEB,0xDF,0xF6,0xC3,0x40,0x75,0x0C,0x8B,0xD8,0x83,0xEB,0x08,0xD1,0xE3,0x2E,0xFF,
+0xA7,0xD4,0x3F,0xFF,0x46,0x66,0x2C,0x20,0xEB,0xC7,0x85,0xC0,0x74,0x2C,0x89,0x46,
+0x6A,0x83,0x4E,0x48,0x40,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29,0x7E,
+0x24,0x80,0x7E,0x26,0x02,0x74,0x08,0x83,0x66,0x26,0xFD,0xE8,0xA3,0x01,0xC3,0x60,
+0xB0,0xFD,0xE8,0x31,0x02,0x61,0xE8,0x98,0x01,0xC3,0xE9,0x57,0xFF,0x90,0x8B,0x5E,
+0x66,0x4B,0x78,0x03,0x89,0x5E,0x66,0xAA,0x8B,0x5E,0x64,0xF7,0xC3,0x00,0x20,0x75,
+0x03,0xE9,0x40,0xFF,0xF7,0xC3,0x40,0x00,0x74,0x08,0x8A,0x86,0xC1,0x00,0xAA,0xE9,
+0x32,0xFF,0xB8,0x32,0x00,0xEB,0xA3,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x83,0xC3,
+0x08,0x80,0xE3,0xF8,0x89,0x5E,0x66,0x8B,0x5E,0x64,0x81,0xE3,0x00,0x18,0x81,0xFB,
+0x00,0x18,0x74,0x2D,0xAA,0x85,0xDB,0x74,0x25,0xF7,0x46,0x64,0x40,0x00,0x75,0x18,
+0x81,0xFB,0x00,0x10,0x74,0x0C,0x8B,0x46,0x66,0x2B,0x46,0x68,0xC1,0xE0,0x04,0xE9,
+0x68,0xFF,0xB8,0x64,0x00,0xE9,0x62,0xFF,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0xE3,
+0xFE,0x51,0x8B,0x4E,0x66,0x2B,0x4E,0x68,0xB0,0x20,0xF3,0xAA,0x59,0xE9,0xD4,0xFE,
+0x8B,0x5E,0x66,0x89,0x5E,0x68,0x8B,0x5E,0x64,0xF7,0xC3,0x24,0x00,0x74,0x10,0xC7,
+0x46,0x66,0x00,0x00,0xF7,0xC3,0x04,0x00,0x74,0x05,0xB0,0x0D,0xAA,0xB0,0x0A,0xAA,
+0xEB,0x48,0x90,0x90,0xAA,0xF7,0x46,0x64,0x00,0x40,0x74,0x06,0xB8,0xD0,0x07,0xE9,
+0x18,0xFF,0xE9,0x9F,0xFE,0x90,0xAA,0xF7,0x46,0x64,0x00,0x80,0x74,0x06,0xB8,0xD0,
+0x07,0xE9,0x06,0xFF,0xE9,0x8D,0xFE,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x85,0xDB,
+0x75,0x0C,0x8B,0x5E,0x64,0xF7,0xC3,0x10,0x00,0x74,0x06,0xE9,0x76,0xFE,0x8B,0x5E,
+0x64,0xF7,0xC3,0x08,0x00,0x74,0x27,0xB0,0x0A,0xAA,0xF7,0xC3,0x20,0x00,0x75,0x1F,
+0xF7,0xC3,0x00,0x01,0x75,0x03,0xE9,0x5B,0xFE,0xF7,0xC3,0x40,0x00,0x75,0x06,0xB8,
+0x64,0x00,0xE9,0xC5,0xFE,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0x46,0xFE,0xAA,0xC7,
+0x46,0x66,0x00,0x00,0xF7,0xC3,0x00,0x06,0x74,0xF1,0xF7,0xC3,0x40,0x00,0x74,0x19,
+0x8A,0x86,0xC1,0x00,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00,0x04,0x72,0x06,0x76,0x02,
+0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xE9,0x1B,0xFE,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00,
+0x04,0x72,0x0E,0x76,0x06,0xB8,0x96,0x00,0xE9,0x7F,0xFE,0xB8,0x64,0x00,0xE9,0x79,
+0xFE,0x8B,0x46,0x68,0xE9,0x73,0xFE,0x90,0x36,0x8B,0x0E,0xDA,0x12,0x83,0xF9,0x32,
+0x73,0x1D,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8D,0x76,0x4C,0xBF,0xDC,0x12,
+0x03,0xF9,0xA5,0xA5,0xA5,0x83,0xC1,0x06,0x89,0x0E,0xDA,0x12,0x07,0x1F,0xC3,0xB0,
+0x08,0xE8,0x6E,0xCD,0xC3,0x90,0x83,0x66,0x48,0xFE,0xE8,0x93,0xC4,0xE8,0xC8,0xFF,
+0xC3,0xF6,0x46,0x27,0x02,0x75,0x0F,0x9C,0xFA,0x83,0x7E,0x1A,0x00,0x74,0x09,0x80,
+0x4E,0x27,0x01,0x9D,0xF9,0xC3,0xF8,0xC3,0x50,0x52,0xF7,0x46,0x38,0x40,0x00,0x74,
+0x1D,0xE8,0x34,0xDE,0x83,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x27,0x83,0xEA,0x08,0x8A,
+0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x5A,0x58,0xEB,0xD1,0xE8,0x0C,
+0xDE,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x5A,
+0x58,0xEB,0xBC,0x80,0x4E,0x27,0x02,0x5A,0x58,0x9D,0xF8,0xC3,0x08,0x46,0x26,0x9C,
+0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00,0x75,0x14,0xF6,0xC1,0x06,0x74,
+0x23,0xE8,0xD9,0xDD,0x8A,0xC1,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3,
+0xF6,0xC1,0x02,0x74,0x0F,0xE8,0xD0,0xDD,0x83,0xC2,0x02,0x8A,0xC1,0x24,0xFD,0x88,
+0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x8B,0x5E,0x26,0x22,0xC3,0x88,0x46,0x26,0x74,0x01,
+0xC3,0x80,0x66,0x27,0xFD,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00,
+0x75,0x16,0xF6,0xC1,0x04,0x75,0x0F,0xE8,0x93,0xDD,0x8A,0xC1,0x24,0xFD,0x0C,0x04,
+0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3,0xF6,0xC1,0x02,0x75,0xF9,0xE8,0x88,0xDD,
+0x83,0xC2,0x0A,0xEC,0xA8,0x20,0x75,0x0E,0x83,0xEA,0x08,0x8A,0xC1,0x0C,0x02,0x88,
+0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x83,0xEA,0x0A,0x33,0xC9,0x8A,0x4E,0x1C,0x8B,0x46,
+0x1A,0x3B,0xC8,0x73,0x1B,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0x1E,0xC5,0x76,
+0x00,0xF3,0x6E,0x1F,0x89,0x76,0x00,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0xEB,0xCD,
+0x85,0xC0,0x74,0x12,0x01,0x46,0x2A,0x8B,0xC8,0x1E,0xC5,0x76,0x00,0xF3,0x6E,0x1F,
+0x89,0x76,0x00,0x89,0x4E,0x1A,0xF6,0xC7,0x01,0x75,0x23,0x80,0xCB,0x02,0x89,0x5E,
+0x26,0xE8,0x08,0xC3,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88,0x86,
+0xA5,0x00,0xF6,0xC7,0x10,0x75,0x05,0xB0,0x02,0xE8,0x16,0xCC,0x9D,0xC3,0x83,0xC2,
+0x02,0x8A,0x86,0xA5,0x00,0xEB,0x86,0x90,0x8B,0xD1,0x8B,0x46,0x24,0x3B,0xC8,0x76,
+0x02,0x8B,0xC8,0x2B,0xD1,0x2B,0xC1,0x8B,0xD9,0xE3,0x22,0x80,0x66,0x27,0xFD,0x8E,
+0x46,0x02,0x8B,0x7E,0x22,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3,
+0xA5,0x73,0x01,0xA4,0x89,0x7E,0x22,0x89,0x46,0x24,0x01,0x5E,0x1A,0x8B,0xCA,0x80,
+0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0xF6,0xFE,
+0x61,0xC3,0x50,0xE4,0x0A,0x84,0xC0,0x75,0x0A,0x86,0x86,0xA1,0x00,0x84,0xC0,0x74,
+0x0A,0xE6,0x0A,0x58,0x0C,0x20,0x89,0x46,0x48,0xF9,0xC3,0x58,0x24,0xDF,0x89,0x46,
+0x48,0xF8,0xC3,0x90,0xFB,0xB0,0x02,0xE8,0xE8,0x07,0xFA,0xE8,0x2E,0x01,0xFB,0xB0,
+0x01,0xE8,0xDE,0x07,0xFA,0xB0,0x02,0xE8,0xBC,0xCB,0xFB,0x85,0xED,0x74,0xE5,0xFA,
+0x8E,0x5E,0x0A,0xFB,0x90,0xFA,0x8B,0x46,0x48,0x8B,0x76,0x40,0xA8,0x8C,0x75,0xDE,
+0xA8,0x20,0x74,0x1A,0x50,0xE8,0x55,0xDC,0x58,0xE8,0xA6,0xFF,0x73,0x10,0xB0,0x02,
+0xE8,0x5F,0xCB,0xEB,0xC9,0x90,0x25,0xFF,0x00,0x8B,0xC8,0xEB,0x36,0x90,0xA8,0x01,
+0x75,0x22,0x46,0x83,0xE6,0xFE,0x3B,0x76,0x08,0x74,0x79,0xAD,0x8A,0xFC,0xB3,0xF0,
+0x22,0xFB,0x3A,0xFB,0x74,0xE0,0x3A,0xBE,0xA0,0x00,0x74,0x2E,0xE8,0xD2,0xFD,0x73,
+0x77,0xEB,0x9B,0x90,0x8A,0xE0,0x24,0xFC,0x88,0x46,0x48,0x8B,0x4E,0x4A,0xF6,0xC4,
+0x02,0x74,0x1D,0xE8,0xBB,0xFD,0x72,0x86,0xE8,0x13,0xF3,0x89,0x76,0x40,0xE3,0x93,
+0x83,0x4E,0x48,0x03,0x89,0x4E,0x4A,0xE9,0x74,0xFF,0x25,0xFF,0x0F,0x8B,0xC8,0x90,
+0x8B,0x86,0x98,0x00,0x85,0xC0,0x74,0x1A,0x51,0x8A,0x8E,0xA0,0x00,0xC0,0xE9,0x04,
+0xBA,0x01,0x00,0xD3,0xE2,0x59,0x23,0xC2,0x74,0x08,0x03,0xF1,0x89,0x76,0x40,0xE9,
+0x61,0xFF,0xFF,0x56,0x62,0xE3,0xF5,0x83,0x4E,0x48,0x01,0x89,0x4E,0x4A,0x89,0x76,
+0x40,0xE9,0x3A,0xFF,0x81,0x4E,0x26,0x00,0x10,0x8B,0x46,0x50,0x3B,0x46,0x46,0x77,
+0x03,0xE8,0x52,0xFD,0xE9,0x27,0xFF,0x90,0x88,0xBE,0xA0,0x00,0xEB,0xAC,0x0A,0x06,
+0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xB0,0x04,0xEE,0xEC,0x84,0xC0,0x75,0x12,0xB0,
+0x04,0xEE,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0x06,0xC7,0x06,0x84,0x12,0x00,
+0x00,0x88,0x26,0x90,0x12,0xC3,0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xEC,
+0xA8,0x01,0x75,0xED,0xBA,0x08,0x01,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0xE1,
+0xC7,0x06,0x84,0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x90,0x36,0xF7,0x06,0x24,
+0x01,0x01,0x00,0x75,0x30,0x36,0x8B,0x0E,0xDA,0x12,0x80,0xF9,0x36,0x73,0x26,0x33,
+0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0xDC,0x12,0x03,0xF9,0xB0,0x08,0xE8,0x77,0xCA,0x85,
+0xED,0x74,0x0E,0x8D,0x76,0x4C,0xA5,0xA5,0xA5,0x80,0xC1,0x06,0x80,0xF9,0x36,0x72,
+0xE9,0x89,0x0E,0xDA,0x12,0xC3,0xC3,0x90,0xF7,0x06,0x26,0x01,0x01,0x00,0x75,0xF6,
+0x8B,0x0E,0x20,0x13,0x85,0xC9,0x75,0xEE,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x24,
+0x13,0xB9,0x36,0x00,0xB0,0x0A,0xE8,0x3D,0xCA,0x85,0xED,0x75,0x06,0xE9,0x12,0x01,
+0xE9,0x0A,0x01,0x33,0xDB,0x8A,0x46,0x4C,0x8A,0xA6,0xB3,0x00,0xFE,0xCC,0x78,0x0E,
+0x88,0xA6,0xB3,0x00,0x0A,0xDC,0xB4,0x0A,0xAB,0x83,0xE9,0x02,0x76,0xE2,0x8A,0xA6,
+0xB2,0x00,0xFE,0xCC,0x78,0x0E,0x88,0xA6,0xB2,0x00,0x0A,0xDC,0xB4,0x08,0xAB,0x83,
+0xE9,0x02,0x76,0xCC,0x8A,0xA6,0xB1,0x00,0xFE,0xCC,0x78,0x18,0x8A,0xBE,0xB0,0x00,
+0x75,0x04,0x88,0xA6,0xB0,0x00,0x88,0xA6,0xB1,0x00,0x0A,0xDC,0x8A,0xE7,0xAB,0x83,
+0xE9,0x02,0x76,0xAC,0x8A,0xA6,0xB4,0x00,0xFE,0xCC,0x78,0x1F,0x88,0xA6,0xB4,0x00,
+0x0A,0xDC,0xB4,0x0B,0xAB,0x8A,0x86,0xBC,0x00,0x8A,0xA6,0xBD,0x00,0xAB,0x8B,0x86,
+0xBE,0x00,0xAB,0x83,0xE9,0x06,0x76,0x88,0x8A,0x46,0x4C,0x8A,0xA6,0xB6,0x00,0xFE,
+0xCC,0x78,0x19,0x88,0xA6,0xB6,0x00,0x0A,0xDC,0xB4,0x0C,0xAB,0xE8,0xDB,0xCB,0xAB,
+0x8B,0x46,0x2A,0xAB,0x83,0xE9,0x06,0x76,0x74,0x8A,0x46,0x4C,0x8A,0xA6,0xB7,0x00,
+0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB7,0x00,0x0A,0xDC,0xB4,0x0D,0xAB,0xE8,0xBA,0xCB,
+0xAB,0x8B,0x46,0x34,0xAB,0x83,0xE9,0x06,0x76,0x53,0x8A,0x46,0x4C,0x8A,0xA6,0xB8,
+0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB8,0x00,0x0A,0xDC,0xB4,0x0E,0xAB,0xA1,0x50,
+0x12,0xAB,0xA1,0x52,0x12,0xAB,0x83,0xE9,0x06,0x76,0x32,0x8A,0x46,0x4C,0x8A,0xA6,
+0xB5,0x00,0xFE,0xCC,0x78,0x18,0x88,0xA6,0xB5,0x00,0x0A,0xDC,0xB4,0x0F,0xAB,0x8B,
+0x86,0x9A,0x00,0xAB,0x8B,0x86,0x9C,0x00,0xAB,0x83,0xE9,0x06,0x76,0x0F,0x84,0xDB,
+0x75,0x03,0xE9,0xEF,0xFE,0xB0,0x0A,0xE8,0xF8,0xC8,0xE9,0xE7,0xFE,0xB0,0x0A,0xE8,
+0xF0,0xC8,0xF7,0xD9,0x83,0xC1,0x36,0x8B,0xC1,0x0D,0x80,0x00,0x86,0xC4,0xA3,0x22,
+0x13,0x41,0x41,0x89,0x0E,0x20,0x13,0xC3,0xA1,0x84,0x12,0x2B,0xC1,0x72,0x11,0xA3,
+0x84,0x12,0xBE,0x22,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x20,0x13,0xF8,0xC3,
+0xF9,0xC3,0xC3,0x81,0xEF,0x6A,0x13,0x74,0xF9,0x8B,0xC7,0x0D,0x80,0x00,0x86,0xC4,
+0xA3,0x68,0x13,0x47,0x47,0x89,0x3E,0x66,0x13,0xC3,0xF7,0x06,0x2A,0x01,0x01,0x00,
+0x75,0xE0,0x8B,0x0E,0x66,0x13,0xE3,0x07,0x80,0xF9,0x20,0x77,0xD5,0x49,0x49,0x33,
+0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x6A,0x13,0x8B,0xF7,0x03,0xF9,0x83,0xC6,0x34,0x3B,
+0xFE,0x77,0xC0,0xB0,0x0E,0xE8,0xAE,0xC8,0x85,0xED,0x74,0xB7,0x8A,0x46,0x4C,0x8A,
+0xB6,0xB9,0x00,0xFE,0xCE,0x78,0x15,0x88,0xB6,0xB9,0x00,0x8A,0xA6,0xA9,0x00,0x80,
+0xCC,0xC0,0xAB,0x84,0xF6,0x74,0x05,0xB0,0x0E,0xE8,0x56,0xC8,0x8A,0xB6,0xBA,0x00,
+0xFE,0xCE,0x78,0xCB,0x8A,0x9E,0xA9,0x00,0x8A,0xBE,0xAB,0x00,0x8A,0x56,0x3F,0x8A,
+0xF3,0x32,0xF7,0x0A,0xB6,0xAC,0x00,0xC6,0x86,0xAC,0x00,0x00,0x22,0xF2,0x74,0x4B,
+0xF6,0xC6,0x08,0x74,0x0F,0xB4,0x02,0xF6,0xC3,0x08,0x75,0x02,0xB4,0x03,0xAB,0x80,
+0xE6,0xF7,0x74,0x37,0xF6,0xC6,0x01,0x74,0x0F,0xB4,0x00,0xF6,0xC3,0x01,0x75,0x02,
+0xB4,0x01,0xAB,0x80,0xE6,0xFE,0x74,0x23,0xF6,0xC6,0x02,0x74,0x0F,0xB4,0x04,0xF6,
+0xC3,0x02,0x75,0x02,0xB4,0x05,0xAB,0x80,0xE6,0xFD,0x74,0x0F,0xF6,0xC6,0x04,0x74,
+0x0A,0xB4,0x06,0xF6,0xC3,0x04,0x75,0x02,0xB4,0x07,0xAB,0xC6,0x86,0xBA,0x00,0x00,
+0x88,0x9E,0xAB,0x00,0xE9,0x58,0xFF,0x90,0xA1,0x84,0x12,0x2B,0xC1,0x72,0x11,0xA3,
+0x84,0x12,0xBE,0x68,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x66,0x13,0xF8,0xC3,
+0xF9,0xC3,0xA1,0x84,0x12,0x41,0x41,0x2B,0xC1,0x72,0x23,0xA3,0x84,0x12,0x8B,0xC1,
+0x48,0x48,0x32,0xE4,0x0C,0x80,0x86,0xC4,0xEF,0x90,0x90,0x90,0x90,0x90,0xBE,0xDC,
+0x12,0x49,0x49,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0xDA,0x12,0xF8,0xC3,0xF9,0xC3,
+0x8A,0xC8,0x8A,0x46,0x4C,0xB4,0x01,0x83,0xEB,0x06,0xEF,0x90,0x90,0x90,0x90,0x90,
+0xB8,0x01,0x00,0xEF,0x90,0x90,0x90,0x90,0x90,0x8A,0xC1,0xEF,0x90,0x90,0x90,0x90,
+0x90,0xE9,0x97,0x00,0xE9,0xAC,0x00,0x33,0xC0,0x8E,0xD8,0x89,0x1E,0x84,0x12,0xC3,
+0x36,0x8B,0x1E,0x84,0x12,0xFB,0x90,0xFA,0xB0,0x0C,0xE8,0x89,0xC7,0x85,0xED,0x74,
+0xE6,0xC5,0x76,0x0C,0x83,0xFB,0x14,0x72,0xDB,0xFB,0x90,0xFA,0xAD,0x85,0xC0,0x78,
+0xAF,0x74,0xE2,0x8B,0xFE,0x03,0xF8,0x36,0x8B,0x0E,0x86,0x12,0x3B,0xC1,0x77,0x02,
+0x8B,0xC8,0x83,0xEB,0x04,0x3B,0xD9,0x77,0x02,0x8B,0xCB,0x33,0xC0,0x8A,0x46,0x4C,
+0xEF,0x90,0x90,0x90,0x90,0x90,0x8B,0xC1,0xEF,0x90,0x90,0x90,0x90,0x90,0x41,0x80,
+0xE1,0xFE,0x2B,0xD9,0x51,0xD1,0xE9,0xF3,0x6F,0x90,0x59,0x8B,0xC7,0x40,0x24,0xFE,
+0x3B,0xC6,0x74,0x27,0x2B,0xFE,0x4E,0x4E,0x53,0x8B,0x5E,0x10,0x3B,0xF3,0x72,0x13,
+0x03,0x1F,0x83,0xC3,0x03,0x80,0xE3,0xFE,0xC7,0x07,0x00,0x00,0x83,0x6E,0x74,0x02,
+0x89,0x5E,0x10,0x5B,0x89,0x3C,0x89,0x76,0x0C,0xEB,0x89,0x89,0x76,0x0C,0x39,0x76,
+0x10,0x77,0x81,0x72,0x08,0x83,0x3C,0x00,0x74,0x03,0xE9,0x77,0xFF,0xE8,0x0D,0xBE,
+0xE9,0x62,0xFF,0x36,0x89,0x1E,0x84,0x12,0xB0,0x0C,0xE8,0xB5,0xC6,0x33,0xC0,0x8E,
+0xD8,0xC3,0xA1,0x84,0x12,0x3D,0x10,0x00,0x72,0x77,0xBA,0x04,0x01,0x3B,0x06,0x88,
+0x12,0x75,0x06,0xC7,0x06,0x7E,0x12,0x00,0x00,0x8B,0x0E,0xDA,0x12,0xE3,0x0B,0xE8,
+0xD0,0xFE,0x72,0x57,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x20,0x13,0xE3,0x0B,
+0xE8,0xA5,0xFD,0x72,0x46,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x66,0x13,0xE3,
+0x0B,0xE8,0x94,0xFE,0x72,0x35,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0xA1,0x28,0x01,0xA9,
+0x01,0x00,0x75,0x03,0xE8,0xF9,0xFE,0x80,0x3E,0x8D,0x12,0x00,0x75,0x1D,0xA1,0x84,
+0x12,0x3D,0x20,0x00,0x76,0x15,0x3B,0x06,0x82,0x12,0x76,0x09,0xA1,0x7E,0x12,0x3B,
+0x06,0x80,0x12,0x72,0x0C,0x80,0x0E,0x90,0x12,0x80,0xC3,0xB0,0x80,0xFF,0x16,0x7C,
+0x12,0xC3,0x80,0x0E,0x90,0x12,0x40,0xC3,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x17,
+0x9C,0x0E,0xE8,0xB7,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x20,0x9C,0x0E,0xE8,
+0xAA,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x16,0x9C,0x0E,0xE8,0x9D,0xC8,0x90,
+0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xCA,0xFB,0x90,0xFA,0xBA,0x04,0x01,0xED,0x90,
+0x90,0x90,0x90,0x90,0x3A,0x06,0x94,0x12,0x77,0xBE,0x33,0xDB,0x8A,0xD8,0xD1,0xE3,
+0x2E,0x8B,0xAF,0x44,0x00,0xC4,0x7E,0x08,0x85,0xFF,0x74,0xB9,0xF6,0xC4,0xC0,0x75,
+0x55,0x32,0xC0,0xC1,0xE0,0x02,0x80,0xE4,0xF0,0x8B,0xF0,0xED,0x90,0x90,0x90,0x90,
+0x90,0x85,0xC0,0x74,0xBB,0x8B,0xC8,0x41,0x80,0xE1,0xFE,0x0B,0xC6,0x8B,0x5E,0x50,
+0x4B,0x4B,0x2B,0xD9,0x78,0x9C,0xAB,0x8B,0xC1,0x40,0x40,0x01,0x46,0x4E,0xD1,0xE9,
+0xF3,0x6D,0x90,0x89,0x5E,0x50,0x89,0x7E,0x08,0x8B,0x46,0x26,0x80,0xE4,0xEF,0x89,
+0x46,0x26,0xF6,0xC4,0x01,0x75,0x0C,0xF7,0x46,0x48,0x0C,0x00,0x75,0x05,0xB0,0x02,
+0xE8,0x7F,0xC5,0xE9,0x7A,0xFF,0x86,0xC4,0x8B,0xC8,0x83,0xE1,0x3F,0x41,0x80,0xE1,
+0xFE,0xE3,0x0A,0x3C,0x80,0x72,0x09,0x24,0x3F,0xB4,0xF0,0xEB,0xB0,0xE9,0x60,0xFF,
+0x25,0x3F,0x00,0x33,0xFF,0x8E,0xC7,0xBF,0x96,0x12,0x8B,0xF7,0xD1,0xE9,0xF3,0x6D,
+0x90,0x8B,0xC8,0xE8,0x48,0xED,0xE9,0x47,0xFF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93,
+0x12,0x1B,0x9C,0x0E,0xE8,0xD5,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,
+0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xB0,0x06,0xEE,0xEC,0xA2,0x8C,0x12,
 0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,0x00,0xE8,
-0x12,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0xB6,0xFE,0xB8,0x00,0x80,0xBA,
-0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xEE,0x86,0xE0,0xEE,0x86,0xE0,0xEC,0x86,
-0xE0,0xEC,0x86,0xE0,0x80,0xE1,0xFE,0xF3,0x6C,0x90,0x80,0xE1,0xFE,0xF3,0x6E,0x90,
-0x05,0x00,0x57,0x47,0x8A,0x4B,0x05,0x00,0x57,0x48,0x8A,0x4B,0x05,0x00,0x85,0x48,
-0x8A,0x4B,0x05,0x00,0x17,0x49,0x8A,0x4B,0x06,0x00,0x7A,0x48,0x78,0x4B,0x06,0x00,
-0x9C,0x48,0x78,0x4B,0x06,0x00,0xA5,0x48,0x78,0x4B,0x06,0x00,0xAD,0x48,0x78,0x4B,
-0x06,0x00,0x02,0x49,0x78,0x4B,0x06,0x00,0x0A,0x49,0x78,0x4B,0x06,0x00,0x30,0x4A,
-0x7E,0x4B,0x06,0x00,0x5D,0x4A,0x7E,0x4B,0x05,0x00,0x80,0x4A,0x84,0x4B,0x05,0x00,
-0xCE,0x4A,0x84,0x4B,0x00,0x00,0x1E,0x06,0x83,0x3E,0x44,0x12,0x00,0x74,0x09,0xA0,
-0x06,0x01,0x24,0x30,0x3C,0x30,0x74,0x1A,0x8C,0xC8,0x8E,0xD8,0x8E,0xC0,0xBB,0x90,
-0x4B,0x8B,0x0F,0xE3,0x0D,0x8B,0x7F,0x02,0x8B,0x77,0x04,0xF3,0xA4,0x83,0xC3,0x06,
-0xEB,0xEF,0x07,0x1F,0xC3,0x90,0x33,0xC0,0xA3,0x3E,0x01,0xB9,0x0C,0x01,0xBE,0x40,
-0x01,0x8B,0xFE,0x81,0xC6,0xB4,0x0F,0x89,0x04,0x8B,0xC6,0x2B,0xF1,0x3B,0xC7,0x77,
-0xF6,0xA3,0x3C,0x01,0xC3,0x90,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x8B,0x5E,
-0x00,0x3B,0xEB,0x74,0x2B,0x8B,0x76,0x02,0x89,0x1C,0x89,0x77,0x02,0x36,0xA1,0x3C,
-0x01,0x89,0x46,0x00,0x36,0x89,0x2E,0x3C,0x01,0x8B,0xEB,0xFF,0x4E,0x06,0x74,0x08,
-0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,
-0x61,0x07,0x1F,0xC3,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x98,0x89,0x46,0x06,
-0x89,0x66,0x04,0x3B,0x6E,0x00,0x74,0x10,0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,
-0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07,0x1F,0xC3,0xC3,0x90,0x1E,0x06,
-0x60,0x9C,0xFA,0x33,0xED,0x8E,0xDD,0x8B,0x2E,0x3C,0x01,0x85,0xED,0x74,0x3D,0x8B,
-0x4E,0x00,0x89,0x0E,0x3C,0x01,0x8B,0xCC,0x8D,0xA6,0x0A,0x01,0x56,0x1E,0x06,0x60,
-0x89,0x66,0x04,0xC7,0x46,0x08,0x0F,0x1A,0xC7,0x46,0x06,0x01,0x00,0x8B,0x1E,0x3E,
-0x01,0x85,0xDB,0x74,0x1D,0x8B,0xC5,0x87,0x07,0x89,0x46,0x00,0x89,0x5E,0x02,0x8B,
-0xD8,0x89,0x6F,0x02,0x8B,0xE1,0x9D,0x61,0x07,0x1F,0xF8,0xC3,0x9D,0x61,0x07,0x1F,
-0xF9,0xC3,0x89,0x2E,0x3E,0x01,0x89,0x6E,0x00,0x89,0x6E,0x02,0x87,0xE1,0x9D,0x8B,
-0xE1,0xEB,0xE4,0x00,0x0D,0x0A,0x54,0x65,0x72,0x6D,0x69,0x6E,0x61,0x6C,0x73,0x20,
-0x73,0x75,0x70,0x70,0x6F,0x72,0x74,0x65,0x64,0x3A,0x0D,0x0A,0x31,0x29,0x20,0x41,
-0x4E,0x53,0x49,0x20,0x63,0x6F,0x6D,0x70,0x61,0x74,0x69,0x62,0x6C,0x65,0x0D,0x0A,
-0x32,0x29,0x20,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x0D,0x0A,0x50,0x6C,0x65,0x61,
-0x73,0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x3A,0x20,0x00,0x0D,0x0A,0x63,0x6F,
-0x64,0x65,0x20,0x73,0x65,0x67,0x6D,0x65,0x6E,0x74,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,
-0x6E,0x69,0x74,0x6F,0x72,0x20,0x76,0x32,0x2E,0x35,0x0A,0x0D,0x0A,0x3E,0x00,0x0D,
-0x0A,0x50,0x61,0x72,0x64,0x6F,0x6E,0x3F,0x00,0x0D,0x0A,0x4E,0x6F,0x20,0x61,0x64,
-0x64,0x72,0x65,0x73,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x00,
-0x0D,0x0A,0x3A,0x00,0x0D,0x0A,0x00,0x4C,0x6F,0x63,0x3D,0x00,0x0D,0x0A,0x46,0x41,
-0x54,0x41,0x4C,0x20,0x45,0x52,0x52,0x4F,0x52,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E,
-0x69,0x74,0x6F,0x72,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x73,0x3A,0x2D,0x0D,
-0x0A,0x20,0x20,0x20,0x44,0x2C,0x64,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,
-0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x6D,0x65,0x6D,0x6F,
-0x72,0x79,0x0D,0x0A,0x20,0x20,0x20,0x4C,0x2C,0x6C,0x5B,0x5B,0x78,0x78,0x78,0x78,
-0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x73,
-0x69,0x6E,0x67,0x6C,0x65,0x20,0x6C,0x69,0x6E,0x65,0x0D,0x0A,0x20,0x20,0x20,0x45,
-0x2C,0x65,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,
-0x2D,0x20,0x65,0x64,0x69,0x74,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x0D,0x0A,0x20,
-0x20,0x20,0x46,0x2C,0x66,0x5B,0x5B,0x78,0x78,0x78,0x78,0x20,0x5D,0x78,0x78,0x78,
-0x78,0x5D,0x20,0x2D,0x20,0x66,0x69,0x6C,0x6C,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,
-0x20,0x70,0x61,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x0D,0x0A,0x20,0x20,0x20,
-0x49,0x5B,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-0x20,0x2D,0x20,0x77,0x6F,0x72,0x64,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,
-0x6F,0x6D,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x69,0x5B,0x78,0x78,
-0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,
-0x79,0x74,0x65,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,0x70,
-0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x4F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,
-0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,
-0x74,0x20,0x77,0x6F,0x72,0x64,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,
-0x20,0x20,0x20,0x6F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20,0x20,0x20,0x20,
-0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20,0x62,0x79,0x74,
-0x65,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x47,0x5B,
-0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x2D,
-0x20,0x67,0x6F,0x74,0x6F,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x0D,0x0A,0x20,
-0x20,0x20,0x57,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,
-0x20,0x20,0x20,0x2D,0x20,0x77,0x61,0x74,0x63,0x68,0x20,0x61,0x20,0x77,0x6F,0x72,
-0x64,0x0D,0x0A,0x20,0x20,0x20,0x43,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74,0x65,0x72,0x72,0x75,
-0x70,0x74,0x73,0x20,0x6F,0x66,0x66,0x0D,0x0A,0x20,0x20,0x20,0x53,0x20,0x20,0x20,
-0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,
-0x6E,0x74,0x65,0x72,0x72,0x75,0x70,0x74,0x73,0x20,0x6F,0x6E,0x0D,0x0A,0x20,0x20,
-0x20,0x73,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-0x20,0x20,0x2D,0x20,0x73,0x69,0x6E,0x67,0x6C,0x65,0x20,0x73,0x74,0x65,0x70,0x0D,
-0x0A,0x20,0x20,0x20,0x42,0x78,0x78,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B,0x70,0x6F,0x69,0x6E,
-0x74,0x20,0x73,0x65,0x74,0x0D,0x0A,0x20,0x20,0x20,0x62,0x20,0x20,0x20,0x20,0x20,
-0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,
-0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x20,0x63,0x6C,0x65,0x61,0x72,0x0D,0x0A,0x20,
-0x20,0x20,0x52,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-0x20,0x20,0x20,0x2D,0x20,0x72,0x65,0x73,0x74,0x61,0x72,0x74,0x20,0x62,0x72,0x65,
-0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x0D,0x0A,0x20,0x20,0x20,0x72,0x20,0x20,0x20,
-0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x72,
-0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x61,0x74,0x20,0x62,0x72,0x6B,0x70,
-0x74,0x0D,0x0A,0x20,0x20,0x20,0x58,0x2C,0x78,0x20,0x6E,0x20,0x20,0x20,0x20,0x20,
-0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x65,0x78,0x61,0x6D,0x69,0x6E,0x65,
-0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x48,
-0x2C,0x3F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-0x2D,0x20,0x74,0x68,0x69,0x73,0x20,0x6D,0x65,0x73,0x73,0x61,0x67,0x65,0x00,0x1B,
-0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x41,0x4E,0x53,0x49,0x20,0x54,0x65,
-0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x0A,0x00,0x1B,0x5B,0x4B,0x00,0x1B,0x5B,
-0x4A,0x00,0x1B,0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x00,0x1B,0x5B,0x44,
-0x20,0x1B,0x5B,0x44,0x00,0x1B,0x5B,0x31,0x3B,0x37,0x32,0x48,0x00,0x1B,0x5B,0x00,
-0x3B,0x00,0x48,0x00,0x1B,0x5B,0x73,0x00,0x1B,0x5B,0x75,0x00,0x1B,0x7A,0x2B,0x0B,
-0x7F,0x1B,0x7A,0x2E,0x0C,0x7F,0x1B,0x7A,0x2D,0x08,0x7F,0x1B,0x7A,0x2C,0x0A,0x7F,
-0x1B,0x7A,0x22,0x08,0x7F,0x1A,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x20,0x54,0x65,
-0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x00,0x1B,0x54,0x00,0x1B,0x59,0x00,0x1A,
-0x00,0x1E,0x00,0x08,0x20,0x08,0x00,0x00,0x1B,0x3D,0x00,0x00,0x00,0x1B,0x46,0x00,
-0x0D,0x00,0x3F,0x44,0x64,0x45,0x65,0x46,0x66,0x47,0x67,0x48,0x68,0x49,0x69,0x4F,
-0x6F,0x43,0x63,0x53,0x73,0x42,0x62,0x52,0x72,0x57,0x77,0x58,0x78,0x4C,0x6C,0x1E,
-0x60,0xB6,0x57,0xB6,0x57,0x32,0x58,0x32,0x58,0xB8,0x59,0xB8,0x59,0x96,0x59,0x96,
-0x59,0x1E,0x60,0x1E,0x60,0x4E,0x57,0x2A,0x57,0x08,0x57,0xE8,0x56,0x72,0x57,0x72,
-0x57,0x7A,0x57,0x2A,0x5F,0xEE,0x5E,0x3A,0x5F,0x15,0x5F,0x22,0x5F,0x82,0x57,0x82,
-0x57,0xE0,0x59,0xE0,0x59,0xBE,0x57,0xBE,0x57,0x6A,0x61,0x7A,0x61,0xA2,0x61,0xAE,
-0x61,0xBA,0x61,0xD8,0x61,0xE4,0x61,0x04,0x62,0xDA,0x56,0x2C,0x62,0x3A,0x62,0x42,
-0x59,0x20,0x20,0x66,0x6C,0x61,0x67,0x73,0x3D,0x00,0x20,0x20,0x61,0x78,0x3D,0x00,
-0x20,0x20,0x62,0x78,0x3D,0x00,0x20,0x20,0x63,0x78,0x3D,0x00,0x20,0x20,0x64,0x78,
-0x3D,0x00,0x20,0x20,0x63,0x73,0x3D,0x00,0x20,0x20,0x64,0x73,0x3D,0x00,0x20,0x20,
-0x65,0x73,0x3D,0x00,0x20,0x20,0x73,0x73,0x3D,0x00,0x20,0x20,0x64,0x69,0x3D,0x00,
-0x20,0x20,0x73,0x69,0x3D,0x00,0x20,0x20,0x62,0x70,0x3D,0x00,0x20,0x20,0x73,0x70,
-0x3D,0x00,0x20,0x20,0x69,0x70,0x3D,0x00,0x20,0x63,0x68,0x61,0x6E,0x65,0x6C,0x3D,
-0x00,0x20,0x20,0x20,0x20,0x73,0x65,0x67,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,
-0x72,0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F,
-0x6D,0x61,0x78,0x3D,0x00,0x20,0x74,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,
-0x69,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x66,0x3D,0x00,
-0x20,0x74,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x74,0x69,0x5F,0x66,0x6C,0x67,
-0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x70,
-0x63,0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x69,
-0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x72,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,
-0x72,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x69,0x7A,0x3D,
-0x00,0x20,0x72,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x6D,0x69,
-0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00,0x20,0x72,0x69,0x5F,
-0x74,0x6F,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x68,0x72,0x3D,0x00,0x20,0x74,
-0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x74,0x72,0x3D,0x00,
-0x20,0x74,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x69,0x7A,
-0x3D,0x00,0x20,0x74,0x68,0x5F,0x74,0x72,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x66,
-0x6C,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x63,0x6E,0x74,0x3D,0x00,0x20,0x72,0x68,
-0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,
-0x72,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x69,0x7A,0x3D,
-0x00,0x20,0x72,0x68,0x5F,0x73,0x70,0x61,0x3D,0x00,0x20,0x72,0x68,0x5F,0x61,0x73,
-0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,
-0x66,0x6C,0x67,0x3D,0x00,0x20,0x6D,0x5F,0x63,0x61,0x72,0x65,0x3D,0x00,0x20,0x70,
-0x74,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x61,0x73,0x5F,0x66,0x6C,0x6F,0x3D,0x00,
-0x20,0x72,0x6D,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F,0x69,0x6E,
-0x3D,0x00,0x20,0x20,0x71,0x5F,0x6F,0x75,0x74,0x3D,0x00,0x20,0x71,0x5F,0x64,0x72,
-0x61,0x6E,0x3D,0x00,0x20,0x20,0x71,0x5F,0x74,0x69,0x6D,0x3D,0x00,0x20,0x20,0x20,
-0x71,0x5F,0x66,0x63,0x3D,0x00,0x20,0x71,0x5F,0x73,0x74,0x61,0x74,0x3D,0x00,0x20,
-0x71,0x5F,0x64,0x61,0x74,0x61,0x3D,0x00,0x20,0x71,0x5F,0x6D,0x6F,0x64,0x6D,0x3D,
-0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x6F,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,
-0x62,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x65,0x3D,0x00,0x20,0x68,0x61,0x6E,
-0x64,0x5F,0x69,0x3D,0x00,0x20,0x20,0x6F,0x70,0x6F,0x73,0x74,0x3D,0x00,0x20,0x20,
-0x74,0x69,0x6D,0x65,0x6F,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x31,0x3D,0x00,
-0x20,0x63,0x75,0x73,0x74,0x6D,0x32,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x64,
-0x3D,0x00,0x20,0x74,0x78,0x72,0x61,0x74,0x65,0x3D,0x00,0x20,0x72,0x78,0x72,0x61,
-0x74,0x65,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x61,0x70,0x3D,0x00,0x20,0x63,0x5F,
-0x61,0x64,0x64,0x72,0x3D,0x00,0x20,0x63,0x5F,0x61,0x69,0x73,0x72,0x3D,0x00,0x20,
-0x63,0x5F,0x78,0x74,0x61,0x67,0x3D,0x00,0x20,0x63,0x5F,0x64,0x65,0x66,0x72,0x3D,
-0x00,0x20,0x63,0x5F,0x66,0x6C,0x73,0x68,0x3D,0x00,0x20,0x74,0x78,0x6D,0x61,0x78,
-0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x65,0x6D,0x73,0x3D,0x00,0x20,0x20,0x63,0x5F,
-0x6C,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x65,0x72,0x3D,0x00,0x20,0x20,
-0x63,0x5F,0x66,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x63,0x72,0x3D,0x00,
-0x20,0x20,0x63,0x5F,0x6C,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x64,0x73,0x73,
-0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,0x73,0x69,0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,
-0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,
-0x5F,0x63,0x61,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x65,0x66,0x72,0x3D,0x00,0x20,
-0x63,0x5F,0x65,0x72,0x73,0x74,0x3D,0x00,0x20,0x63,0x5F,0x65,0x63,0x6E,0x74,0x3D,
-0x00,0x20,0x63,0x5F,0x62,0x72,0x6B,0x63,0x3D,0x00,0x20,0x63,0x5F,0x62,0x6F,0x6B,
-0x63,0x3D,0x00,0x20,0x63,0x5F,0x72,0x65,0x70,0x6C,0x3D,0x00,0x20,0x63,0x5F,0x63,
-0x63,0x73,0x72,0x3D,0x00,0x20,0x63,0x5F,0x73,0x74,0x74,0x31,0x3D,0x00,0x20,0x63,
-0x5F,0x73,0x74,0x74,0x32,0x3D,0x00,0x2B,0xC0,0x8E,0xD8,0x8E,0xC0,0xE8,0xC2,0x00,
-0xE8,0xE5,0x00,0xFA,0xBF,0x84,0x00,0xC7,0x05,0xBE,0x56,0x8C,0x4D,0x02,0xBF,0x0C,
-0x00,0xC7,0x05,0x50,0x5E,0x8C,0x4D,0x02,0xBF,0x04,0x00,0xC7,0x05,0x9C,0x5E,0x8C,
-0x4D,0x02,0xE8,0xF1,0x00,0x90,0xE8,0x49,0x01,0xE8,0x16,0x00,0xF4,0x90,0xE8,0xE5,
-0x00,0xBE,0x9C,0x4D,0xE8,0x09,0x0C,0xA0,0x93,0x12,0xE8,0x5D,0x0C,0xE8,0xC2,0x09,
-0xEB,0xE4,0xE8,0xD5,0x0C,0xE8,0xC4,0x0C,0x0A,0xC0,0x74,0xF6,0x8B,0x1E,0xF8,0x79,
-0x3C,0x0D,0x74,0x2E,0x3C,0x08,0x74,0x17,0x3C,0x7F,0x74,0x13,0x83,0xFB,0x20,0x7F,
-0xE1,0x88,0x87,0xD6,0x79,0x43,0x89,0x1E,0xF8,0x79,0xE8,0x77,0x0C,0xEB,0xD3,0x0B,
-0xDB,0x74,0xCF,0x4B,0x89,0x1E,0xF8,0x79,0x8B,0x36,0x16,0x7A,0xE8,0xC1,0x0B,0xEB,
-0xC1,0x90,0xE8,0x02,0x00,0xEB,0xBB,0xC6,0x87,0xD6,0x79,0x00,0x0B,0xDB,0x74,0x1E,
-0xA0,0xD6,0x79,0xBF,0x42,0x51,0xB9,0x1D,0x00,0x8B,0xD9,0x06,0x0E,0x07,0xF2,0xAE,
-0x07,0x75,0x17,0x41,0x2B,0xD9,0xD1,0xE3,0x2E,0xFF,0x97,0x5F,0x51,0x90,0x33,0xC0,
-0xA3,0xF8,0x79,0xBE,0x6B,0x4D,0xE8,0x87,0x0B,0xC3,0xBE,0x6F,0x4D,0xE8,0x80,0x0B,
-0xEB,0xEC,0xBA,0x00,0x02,0xB0,0x93,0xEE,0xB0,0x55,0xEE,0xBA,0x10,0x02,0xB0,0x93,
-0xEE,0xB0,0xAA,0xEE,0xBA,0x00,0x02,0xEC,0x3C,0x55,0x75,0x08,0xBA,0x10,0x02,0xEC,
-0x3C,0xAA,0x74,0x03,0xE8,0x2F,0xF6,0xC3,0xBA,0x04,0x02,0xB0,0x1A,0xEE,0xB0,0x20,
-0xEE,0xB0,0x30,0xEE,0xB0,0x40,0xEE,0xB0,0x80,0xEE,0xBA,0x00,0x02,0xB0,0x13,0xEE,
-0xB0,0x07,0xEE,0xBA,0x08,0x02,0xB0,0x80,0xEE,0xBA,0x02,0x02,0xB0,0xBB,0xEE,0xBA,
-0x04,0x02,0xB0,0x05,0xEE,0xC3,0xC6,0x06,0xCA,0x13,0x01,0xC7,0x06,0xF8,0x79,0x00,
-0x00,0xC6,0x06,0xF6,0x79,0x01,0xC7,0x06,0xD0,0x79,0x00,0x00,0xC7,0x06,0xD2,0x79,
-0x00,0x00,0xC7,0x06,0xD4,0x79,0x00,0x00,0xC7,0x06,0xFA,0x79,0x00,0x00,0xC7,0x06,
-0xFC,0x79,0x00,0x00,0xC7,0x06,0xFE,0x79,0x00,0x00,0xC7,0x06,0x00,0x7A,0x00,0x00,
-0xC7,0x06,0x02,0x7A,0xB0,0x59,0x8C,0x0E,0x04,0x7A,0xC7,0x06,0x06,0x7A,0x00,0x00,
-0xC7,0x06,0x27,0x7A,0x00,0x00,0xC6,0x06,0x29,0x7A,0x00,0xC6,0x06,0x2A,0x7A,0x00,
-0xC3,0x90,0xBE,0x04,0x4D,0xE8,0xC8,0x0A,0xE8,0x3F,0x00,0x2C,0x31,0x3C,0x01,0x77,
-0xF7,0xE8,0x81,0x09,0x8B,0x36,0x0C,0x7A,0xE8,0xB5,0x0A,0xBE,0x4C,0x4D,0xE8,0xAF,
-0x0A,0x0E,0x58,0xE8,0xF8,0x0A,0xBE,0x5C,0x4D,0xE8,0xA4,0x0A,0xC3,0x90,0x60,0xD1,
-0xE3,0x83,0xFB,0x18,0x73,0x11,0x1E,0xBA,0x00,0x00,0x8E,0xDA,0x2E,0xFF,0x97,0x99,
-0x51,0x8B,0xEC,0x89,0x46,0x10,0x1F,0x61,0xCF,0x90,0xE8,0x4F,0x0B,0x0A,0xC0,0x75,
-0x05,0xE8,0x56,0x0B,0xEB,0xF4,0xC3,0x90,0x83,0x3E,0xF8,0x79,0x01,0x74,0x16,0xBE,
-0xD7,0x79,0xE8,0x31,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x04,0x3C,0x20,0x75,0x05,
-0xE8,0x23,0x0A,0xEE,0xC3,0xE9,0xD2,0xFE,0x83,0x3E,0xF8,0x79,0x01,0x74,0xF6,0xBE,
-0xD7,0x79,0xE8,0x11,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x08,0x3C,0x20,0x74,0x04,
-0xE9,0xB7,0xFE,0x90,0xE8,0xFF,0x09,0xEF,0xC3,0x90,0x8B,0x16,0x06,0x7A,0x83,0x3E,
-0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xEB,0x09,0x8B,0xD0,0xA3,0x06,0x7A,
-0xB0,0x20,0xE8,0x57,0x0B,0x8B,0x16,0x06,0x7A,0xEC,0xE8,0x6F,0x0B,0xC3,0x8B,0x16,
-0x06,0x7A,0x83,0x3E,0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xC7,0x09,0x8B,
-0xD0,0xA3,0x06,0x7A,0xB0,0x20,0xE8,0x33,0x0B,0x8B,0x16,0x06,0x7A,0xED,0xE8,0x67,
-0x0B,0xC3,0xFA,0xC6,0x06,0xF6,0x79,0x00,0xC3,0x90,0xC6,0x06,0xF6,0x79,0x01,0xFB,
-0xC3,0x90,0x06,0xE8,0x58,0x09,0xB0,0x20,0xE8,0x11,0x0B,0x26,0x8B,0x05,0xE8,0x47,
-0x0B,0xB0,0x08,0xE8,0x06,0x0B,0xE8,0x03,0x0B,0xE8,0x00,0x0B,0xE8,0xFD,0x0A,0xB8,
-0x01,0x00,0xE8,0xCF,0xF4,0xBA,0x02,0x02,0xEC,0x24,0x01,0x75,0x02,0xEB,0xDC,0xBA,
-0x06,0x02,0xEC,0x07,0xC3,0x90,0xC7,0x06,0x08,0x7A,0x10,0x00,0xEB,0x06,0xC7,0x06,
-0x08,0x7A,0x01,0x00,0x06,0x8E,0x06,0xFC,0x79,0x8B,0x3E,0xFA,0x79,0xE8,0x0E,0x09,
-0xE8,0x0B,0x00,0x89,0x3E,0xFA,0x79,0x8C,0x06,0xFC,0x79,0x07,0xC3,0x90,0xBE,0x94,
-0x4D,0xE8,0x7C,0x09,0x8B,0x16,0x08,0x7A,0x52,0xE8,0x2A,0x09,0xE8,0x0F,0x0A,0xE8,
-0x0C,0x0A,0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A,0x01,0xE8,0xBC,0x09,0xE8,0xFD,
-0x09,0x43,0xE2,0xF4,0xE8,0xF7,0x09,0xE8,0xF4,0x09,0x33,0xDB,0xB9,0x10,0x00,0x90,
-0x26,0x8A,0x01,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xE3,
-0x09,0x43,0xE2,0xEC,0xBE,0x94,0x4D,0xE8,0x36,0x09,0x83,0xC7,0x10,0x5A,0x4A,0x75,
-0xB7,0xC3,0x06,0x8E,0x06,0x00,0x7A,0x8B,0x3E,0xFE,0x79,0xE8,0xA0,0x08,0x89,0x3E,
-0xFE,0x79,0x8C,0x06,0x00,0x7A,0x57,0x8B,0x36,0x0E,0x7A,0xE8,0x12,0x09,0xC7,0x06,
-0x08,0x7A,0x10,0x00,0xBA,0x00,0x02,0xE8,0xE8,0x00,0xE8,0x81,0xFF,0x5F,0xBA,0x00,
-0x00,0xE8,0xDE,0x00,0xBE,0x97,0x4D,0xE8,0xF6,0x08,0x8C,0xC0,0xE8,0x3F,0x09,0xB0,
-0x3A,0xE8,0x90,0x09,0x8B,0xC7,0xE8,0x35,0x09,0xE8,0x7E,0x08,0xE8,0xC3,0x00,0x90,
-0xE8,0xB7,0x09,0xE8,0xA6,0x09,0x0A,0xC0,0x74,0xF6,0x3C,0x0B,0x75,0x06,0x83,0xEF,
-0x10,0xEB,0x19,0x90,0x3C,0x0A,0x75,0x06,0x83,0xC7,0x10,0xEB,0x0F,0x90,0x3C,0x0C,
-0x75,0x04,0x47,0xEB,0x07,0x90,0x3C,0x08,0x75,0x24,0x4F,0x90,0x8B,0x36,0xFE,0x79,
-0x8B,0xC7,0x2B,0xC6,0x3D,0x00,0x01,0x72,0xA5,0x3D,0x10,0x01,0x72,0x04,0x83,0xEE,
-0x20,0x90,0x83,0xC6,0x10,0x89,0x36,0xFE,0x79,0x57,0x8B,0xFE,0xEB,0x80,0x3C,0x2E,
-0x75,0x08,0xBA,0x01,0x13,0xE8,0x6A,0x00,0x07,0xC3,0xC6,0x06,0x0A,0x7A,0x02,0x32,
-0xC9,0x90,0x3C,0x30,0x72,0x4C,0x3C,0x39,0x76,0x0C,0x24,0x5F,0x3C,0x41,0x72,0x42,
-0x3C,0x46,0x77,0x3E,0x2C,0x07,0x2C,0x30,0x50,0xE8,0xCC,0x08,0x58,0x02,0xC8,0xFE,
-0x0E,0x0A,0x7A,0x74,0x0F,0xC0,0xE1,0x04,0xE8,0x2F,0x09,0xE8,0x1E,0x09,0x0A,0xC0,
-0x74,0xF6,0xEB,0xCE,0x26,0x88,0x0D,0xE8,0xE0,0x07,0x8A,0xD0,0xE8,0x23,0x00,0x8A,
-0xC1,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xD5,0x08,0xE9,
-0x70,0xFF,0xE8,0xC5,0x07,0xE8,0x0A,0x00,0x26,0x8A,0x05,0xE8,0x7C,0x08,0xE9,0x1D,
-0xFF,0x90,0xF6,0x06,0x26,0x7A,0x02,0x75,0x02,0x86,0xF2,0x52,0x8B,0x36,0x1A,0x7A,
-0xE8,0x0D,0x08,0x5A,0x52,0x8A,0xC6,0x02,0x06,0x24,0x7A,0xF6,0x06,0x26,0x7A,0x01,
-0x75,0x06,0xE8,0x9F,0x08,0xEB,0x0D,0x90,0x32,0xE4,0xE8,0x0D,0x08,0x8B,0x36,0x1C,
-0x7A,0xE8,0xEC,0x07,0x5A,0x8A,0xC2,0x02,0x06,0x25,0x7A,0xF6,0x06,0x26,0x7A,0x01,
-0x75,0x06,0xE8,0x7F,0x08,0xEB,0x06,0x90,0x32,0xE4,0xE8,0xED,0x07,0x8B,0x36,0x1E,
-0x7A,0xE8,0xCC,0x07,0xC3,0x90,0x06,0x8E,0x06,0x04,0x7A,0x8B,0x3E,0x02,0x7A,0xE8,
-0x3C,0x07,0x89,0x3E,0x02,0x7A,0x8C,0x06,0x04,0x7A,0x07,0xFF,0x1E,0x02,0x7A,0xC3,
-0xBE,0x79,0x4D,0xE8,0xAA,0x07,0xCB,0x90,0x06,0x57,0xBE,0xD7,0x79,0xE8,0x66,0x07,
-0x8B,0xD8,0xE8,0x61,0x07,0x8B,0xC8,0x2B,0xCB,0x78,0x11,0x8E,0xC3,0xBF,0x00,0x00,
-0xB8,0xFF,0xFF,0x51,0xB9,0x08,0x00,0xF3,0xAB,0x59,0xE2,0xF7,0x5F,0x07,0xC3,0x90,
-0x06,0xBE,0xD7,0x79,0xE8,0x3F,0x07,0x8B,0xD8,0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00,
-0xBE,0x08,0x52,0xE8,0xF1,0x08,0x8B,0xC3,0xE8,0xDD,0x08,0xB8,0x01,0x00,0xE8,0x73,
-0xF2,0xE8,0xE0,0x08,0xBE,0x11,0x52,0xE8,0xDD,0x08,0x8B,0x47,0x18,0xE8,0xC8,0x08,
-0xBE,0x59,0x52,0xE8,0xD1,0x08,0x8B,0x47,0x26,0xE8,0xBC,0x08,0xBE,0x35,0x52,0xE8,
-0xC5,0x08,0x8B,0x47,0x1E,0xE8,0xB0,0x08,0xBE,0x3E,0x52,0xE8,0xB9,0x08,0x8B,0x47,
-0x20,0xE8,0xA4,0x08,0xBE,0x50,0x52,0xE8,0xAD,0x08,0x8B,0x47,0x24,0xE8,0x98,0x08,
-0xBE,0x62,0x52,0xE8,0xA1,0x08,0x8B,0x47,0x2A,0xE8,0x8C,0x08,0xE8,0x95,0x08,0xBE,
-0x1A,0x52,0xE8,0x92,0x08,0x8B,0x07,0xE8,0x7E,0x08,0xBE,0x23,0x52,0xE8,0x87,0x08,
-0x8B,0x47,0x1A,0xE8,0x72,0x08,0xBE,0x2C,0x52,0xE8,0x7B,0x08,0x8B,0x47,0x1C,0xE8,
-0x66,0x08,0xBE,0x47,0x52,0xE8,0x6F,0x08,0x8B,0x47,0x22,0xE8,0x5A,0x08,0xE8,0x63,
-0x08,0xBE,0xB3,0x52,0xE8,0x60,0x08,0x8B,0x47,0x38,0xE8,0x4B,0x08,0xBE,0x8F,0x52,
-0xE8,0x54,0x08,0x8B,0x47,0x30,0xE8,0x3F,0x08,0xBE,0x98,0x52,0xE8,0x48,0x08,0x8B,
-0x47,0x32,0xE8,0x33,0x08,0xBE,0x86,0x52,0xE8,0x3C,0x08,0x8B,0x47,0x2E,0xE8,0x27,
-0x08,0xBE,0xA1,0x52,0xE8,0x30,0x08,0x8B,0x47,0x34,0xE8,0x1B,0x08,0xE8,0x24,0x08,
-0xBE,0x6B,0x52,0xE8,0x21,0x08,0x8B,0x47,0x04,0xE8,0x0C,0x08,0xBE,0x74,0x52,0xE8,
-0x15,0x08,0x8B,0x47,0x14,0xE8,0x00,0x08,0xBE,0x7D,0x52,0xE8,0x09,0x08,0x8B,0x47,
-0x2C,0xE8,0xF4,0x07,0xBE,0xAA,0x52,0xE8,0xFD,0x07,0x8B,0x47,0x36,0xE8,0xE8,0x07,
-0xBE,0xBC,0x52,0xE8,0xF1,0x07,0x8B,0x47,0x3A,0xE8,0xDC,0x07,0xBE,0xC5,0x52,0xE8,
-0xE5,0x07,0x8B,0x47,0x3C,0xE8,0xD0,0x07,0xE8,0xD9,0x07,0xBE,0xFB,0x52,0xE8,0xD6,
-0x07,0x8B,0x47,0x48,0xE8,0xC1,0x07,0xBE,0xE0,0x52,0xE8,0xCA,0x07,0x8B,0x47,0x42,
-0xE8,0xB5,0x07,0xBE,0xE9,0x52,0xE8,0xBE,0x07,0x8B,0x47,0x44,0xE8,0xA9,0x07,0xBE,
-0x5E,0x53,0xE8,0xB2,0x07,0x8B,0x47,0x4C,0xE8,0x9D,0x07,0xBE,0x67,0x53,0xE8,0xA6,
-0x07,0x8B,0x47,0x4E,0xE8,0x91,0x07,0xBE,0x70,0x53,0xE8,0x9A,0x07,0x8B,0x47,0x50,
-0xE8,0x85,0x07,0xE8,0x8E,0x07,0xBE,0x04,0x53,0xE8,0x8B,0x07,0x8B,0x47,0x4A,0xE8,
-0x76,0x07,0xBE,0xCE,0x52,0xE8,0x7F,0x07,0x8B,0x47,0x08,0xE8,0x6A,0x07,0xBE,0xD7,
-0x52,0xE8,0x73,0x07,0x8B,0x47,0x40,0xE8,0x5E,0x07,0xBE,0xF2,0x52,0xE8,0x67,0x07,
-0x8B,0x47,0x46,0xE8,0x52,0x07,0xE8,0x5B,0x07,0xBE,0x4C,0x53,0xE8,0x58,0x07,0x8B,
-0x47,0x7A,0xE8,0x43,0x07,0xBE,0x1F,0x53,0xE8,0x4C,0x07,0x8B,0x47,0x70,0xE8,0x37,
-0x07,0xBE,0x28,0x53,0xE8,0x40,0x07,0x8B,0x47,0x72,0xE8,0x2B,0x07,0xBE,0x31,0x53,
-0xE8,0x34,0x07,0x8B,0x47,0x74,0xE8,0x1F,0x07,0xE8,0x28,0x07,0xBE,0x0D,0x53,0xE8,
-0x25,0x07,0x8B,0x47,0x0C,0xE8,0x10,0x07,0xBE,0x16,0x53,0xE8,0x19,0x07,0x8B,0x47,
-0x10,0xE8,0x04,0x07,0xBE,0x3A,0x53,0xE8,0x0D,0x07,0x8B,0x47,0x76,0xE8,0xF8,0x06,
-0xBE,0x43,0x53,0xE8,0x01,0x07,0x8B,0x47,0x78,0xE8,0xEC,0x06,0xBE,0x55,0x53,0xE8,
-0xF5,0x06,0x8B,0x47,0x3E,0xE8,0xE0,0x06,0xE8,0xE9,0x06,0xBE,0x79,0x53,0xE8,0xE6,
-0x06,0x8B,0x47,0x52,0xE8,0xD1,0x06,0xBE,0x82,0x53,0xE8,0xDA,0x06,0x8B,0x47,0x54,
-0xE8,0xC5,0x06,0xBE,0x8B,0x53,0xE8,0xCE,0x06,0x8B,0x47,0x56,0xE8,0xB9,0x06,0xBE,
-0x94,0x53,0xE8,0xC2,0x06,0x8B,0x47,0x58,0xE8,0xAD,0x06,0xBE,0x9D,0x53,0xE8,0xB6,
-0x06,0x8B,0x47,0x5A,0xE8,0xA1,0x06,0xBE,0xA6,0x53,0xE8,0xAA,0x06,0x8B,0x47,0x5C,
-0xE8,0x95,0x06,0xE8,0x9E,0x06,0xBE,0xAF,0x53,0xE8,0x9B,0x06,0x8B,0x47,0x5E,0xE8,
-0x86,0x06,0xBE,0xB8,0x53,0xE8,0x8F,0x06,0x8B,0x47,0x60,0xE8,0x7A,0x06,0xBE,0xC1,
-0x53,0xE8,0x83,0x06,0x8B,0x47,0x62,0xE8,0x6E,0x06,0xBE,0xCA,0x53,0xE8,0x77,0x06,
-0x8B,0x47,0x7C,0xE8,0x62,0x06,0xBE,0xD3,0x53,0xE8,0x6B,0x06,0x8B,0x47,0x7E,0xE8,
-0x56,0x06,0xBE,0xDC,0x53,0xE8,0x5F,0x06,0x8B,0x87,0x80,0x00,0xE8,0x49,0x06,0xE8,
-0x52,0x06,0xBE,0x24,0x54,0xE8,0x4F,0x06,0x8B,0x87,0x9E,0x00,0xE8,0x39,0x06,0xBE,
-0xE5,0x53,0xE8,0x42,0x06,0x8B,0x47,0x64,0xE8,0x2D,0x06,0xBE,0xEE,0x53,0xE8,0x36,
-0x06,0x8B,0x47,0x6E,0xE8,0x21,0x06,0xBE,0xF7,0x53,0xE8,0x2A,0x06,0x8B,0x87,0x8E,
-0x00,0xE8,0x14,0x06,0xBE,0x00,0x54,0xE8,0x1D,0x06,0x8B,0x87,0x90,0x00,0xE8,0x07,
-0x06,0xBE,0x09,0x54,0xE8,0x10,0x06,0x8B,0x87,0x92,0x00,0xE8,0xFA,0x05,0xE8,0x03,
-0x06,0xBE,0x12,0x54,0xE8,0x00,0x06,0x8B,0x87,0x94,0x00,0xE8,0xEA,0x05,0xBE,0x1B,
-0x54,0xE8,0xF3,0x05,0x8B,0x87,0x96,0x00,0xE8,0xDD,0x05,0xBE,0x51,0x54,0xE8,0xE6,
-0x05,0x8B,0x87,0x98,0x00,0xE8,0xD0,0x05,0xBE,0x3F,0x54,0xE8,0xD9,0x05,0x8A,0x87,
-0xA0,0x00,0xE8,0xA7,0x05,0xBE,0x36,0x54,0xE8,0xCC,0x05,0x8A,0x47,0x28,0xE8,0x9B,
-0x05,0xBE,0x48,0x54,0xE8,0xC0,0x05,0x8A,0x87,0xA1,0x00,0xE8,0x8E,0x05,0xE8,0xB3,
-0x05,0xBE,0x5A,0x54,0xE8,0xB0,0x05,0x8A,0x87,0xA2,0x00,0xE8,0x7E,0x05,0xBE,0x63,
-0x54,0xE8,0xA3,0x05,0x8A,0x87,0xA3,0x00,0xE8,0x71,0x05,0xBE,0x6C,0x54,0xE8,0x96,
-0x05,0x8A,0x87,0xA4,0x00,0xE8,0x64,0x05,0xBE,0x75,0x54,0xE8,0x89,0x05,0x8A,0x87,
-0xA5,0x00,0xE8,0x57,0x05,0xBE,0x7E,0x54,0xE8,0x7C,0x05,0x8A,0x87,0xA6,0x00,0xE8,
-0x4A,0x05,0xBE,0x87,0x54,0xE8,0x6F,0x05,0x8A,0x87,0xA7,0x00,0xE8,0x3D,0x05,0xBE,
-0x90,0x54,0xE8,0x62,0x05,0x8A,0x87,0xA8,0x00,0xE8,0x30,0x05,0xE8,0x55,0x05,0xBE,
-0x99,0x54,0xE8,0x52,0x05,0x8A,0x87,0xA9,0x00,0xE8,0x20,0x05,0xBE,0xA2,0x54,0xE8,
-0x45,0x05,0x8A,0x87,0xAA,0x00,0xE8,0x13,0x05,0xBE,0xAB,0x54,0xE8,0x38,0x05,0x8A,
-0x87,0xAB,0x00,0xE8,0x06,0x05,0xBE,0xB4,0x54,0xE8,0x2B,0x05,0x8A,0x87,0xAD,0x00,
-0xE8,0xF9,0x04,0xBE,0xBD,0x54,0xE8,0x1E,0x05,0x8A,0x87,0xAE,0x00,0xE8,0xEC,0x04,
-0xBE,0xC6,0x54,0xE8,0x11,0x05,0x8A,0x87,0xAF,0x00,0xE8,0xDF,0x04,0xBE,0xCF,0x54,
-0xE8,0x04,0x05,0x8A,0x87,0xB0,0x00,0xE8,0xD2,0x04,0xE8,0xF7,0x04,0xBE,0xD8,0x54,
-0xE8,0xF4,0x04,0x8A,0x87,0xB1,0x00,0xE8,0xC2,0x04,0xBE,0xE1,0x54,0xE8,0xE7,0x04,
-0x8A,0x87,0xB2,0x00,0xE8,0xB5,0x04,0xBE,0xEA,0x54,0xE8,0xDA,0x04,0x8A,0x87,0xB3,
-0x00,0xE8,0xA8,0x04,0xBE,0xF3,0x54,0xE8,0xCD,0x04,0x8A,0x87,0xBB,0x00,0xE8,0x9B,
-0x04,0xE8,0xC0,0x04,0xBE,0xFC,0x54,0xE8,0xBD,0x04,0x8A,0x87,0xBC,0x00,0xE8,0x8B,
-0x04,0xBE,0x05,0x55,0xE8,0xB0,0x04,0x8A,0x87,0xBE,0x00,0xE8,0x7E,0x04,0xBE,0x0E,
-0x55,0xE8,0xA3,0x04,0x8A,0x87,0xBF,0x00,0xE8,0x71,0x04,0xE8,0x96,0x04,0x07,0xC3,
-0x60,0x06,0x1E,0x16,0x8B,0xEC,0xFF,0x4E,0x16,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,
-0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89,0x2E,0x2D,0x7A,0xE8,0xCB,0x00,0x81,
-0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0xD8,0x00,0xB8,0xE2,0x5E,0xA3,
-0x2B,0x7A,0xE8,0x5D,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A,0x81,0x4E,0x1A,0x00,
-0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90,0x60,0x06,0x1E,0x16,
-0x8B,0xEC,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,
-0xC0,0x89,0x2E,0x2D,0x7A,0x81,0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,
-0x92,0x00,0xB8,0xE2,0x5E,0xA3,0x2B,0x7A,0xE8,0x17,0x00,0x80,0x3E,0x2A,0x7A,0x00,
-0x74,0x0A,0x81,0x4E,0x1A,0x00,0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,
-0xCF,0x90,0xB8,0xF0,0x00,0xE8,0x8C,0xED,0xFF,0x26,0x2B,0x7A,0xC3,0x90,0x06,0x53,
-0x56,0x80,0x3E,0x29,0x7A,0x00,0x74,0x03,0xE8,0x3F,0x00,0xBE,0xD7,0x79,0xE8,0x25,
-0x02,0x8B,0xD8,0xA3,0x27,0x7A,0x2E,0x8A,0x07,0xA2,0x29,0x7A,0xB0,0xCC,0x2E,0x88,
-0x07,0x5E,0x5B,0x07,0xC3,0xC6,0x06,0x2A,0x7A,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A,
-0xC3,0x90,0x8B,0x2E,0x2D,0x7A,0xE8,0x2B,0x00,0xC3,0xC6,0x06,0x2A,0x7A,0x01,0xE8,
-0x08,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A,0xC3,0x90,0x57,0x80,0x3E,0x29,0x7A,0x00,
-0x74,0x0F,0x8B,0x3E,0x27,0x7A,0xA0,0x29,0x7A,0x2E,0x88,0x05,0xC6,0x06,0x29,0x7A,
-0x00,0x5F,0xC3,0x90,0xBE,0x94,0x4D,0xE8,0x06,0x02,0xBE,0xBA,0x51,0xE8,0x00,0x02,
-0xFF,0x76,0x14,0x58,0xE8,0x47,0x02,0xBE,0xC0,0x51,0xE8,0xF3,0x01,0xFF,0x76,0x0E,
-0x58,0xE8,0x3A,0x02,0xBE,0xC6,0x51,0xE8,0xE6,0x01,0xFF,0x76,0x12,0x58,0xE8,0x2D,
-0x02,0xBE,0xCC,0x51,0xE8,0xD9,0x01,0xFF,0x76,0x10,0x58,0xE8,0x20,0x02,0xBE,0xF6,
-0x51,0xE8,0xCC,0x01,0xFF,0x76,0x0A,0x58,0xE8,0x13,0x02,0xBE,0xFC,0x51,0xE8,0xBF,
-0x01,0xFF,0x76,0x0C,0x58,0xE8,0x06,0x02,0xBE,0xB1,0x51,0xE8,0xB2,0x01,0xFF,0x76,
-0x1A,0x58,0xE8,0xF9,0x01,0xBE,0x94,0x4D,0xE8,0xA5,0x01,0xBE,0xD2,0x51,0xE8,0x9F,
-0x01,0xFF,0x76,0x18,0x58,0xE8,0xE6,0x01,0xBE,0xD8,0x51,0xE8,0x92,0x01,0xFF,0x76,
-0x02,0x58,0xE8,0xD9,0x01,0xBE,0xDE,0x51,0xE8,0x85,0x01,0xFF,0x76,0x04,0x58,0xE8,
-0xCC,0x01,0xBE,0xE4,0x51,0xE8,0x78,0x01,0xFF,0x76,0x00,0x58,0xE8,0xBF,0x01,0xBE,
-0xEA,0x51,0xE8,0x6B,0x01,0xFF,0x76,0x06,0x58,0xE8,0xB2,0x01,0xBE,0xF0,0x51,0xE8,
-0x5E,0x01,0xFF,0x76,0x08,0x58,0xE8,0xA5,0x01,0xBE,0x02,0x52,0xE8,0x51,0x01,0xFF,
-0x76,0x16,0x58,0xE8,0x98,0x01,0xBE,0x6B,0x4D,0xE8,0x44,0x01,0xC3,0x90,0xBE,0xAB,
-0x4D,0xE8,0x3C,0x01,0xC3,0x3C,0x00,0x74,0x05,0x3C,0x01,0x74,0x59,0xC3,0xC7,0x06,
-0x0C,0x7A,0xAF,0x50,0xC7,0x06,0x0E,0x7A,0xD2,0x50,0xC7,0x06,0x10,0x7A,0xCA,0x50,
-0xC7,0x06,0x12,0x7A,0xCE,0x50,0xC7,0x06,0x14,0x7A,0xD6,0x50,0xC7,0x06,0x16,0x7A,
-0xDD,0x50,0xC7,0x06,0x18,0x7A,0xE5,0x50,0xC7,0x06,0x1A,0x7A,0xED,0x50,0xC7,0x06,
-0x1C,0x7A,0xF0,0x50,0xC7,0x06,0x1E,0x7A,0xF2,0x50,0xC7,0x06,0x20,0x7A,0xF4,0x50,
-0xC7,0x06,0x22,0x7A,0xF8,0x50,0xC6,0x06,0x24,0x7A,0x01,0xC6,0x06,0x25,0x7A,0x01,
-0xC6,0x06,0x26,0x7A,0x03,0xC3,0xC7,0x06,0x0C,0x7A,0xFC,0x50,0xC7,0x06,0x0E,0x7A,
-0x2F,0x51,0xC7,0x06,0x10,0x7A,0x29,0x51,0xC7,0x06,0x12,0x7A,0x2C,0x51,0xC7,0x06,
-0x14,0x7A,0x31,0x51,0xC7,0x06,0x16,0x7A,0x33,0x51,0xC7,0x06,0x18,0x7A,0x37,0x51,
-0xC7,0x06,0x1A,0x7A,0x38,0x51,0xC7,0x06,0x1C,0x7A,0x3B,0x51,0xC7,0x06,0x1E,0x7A,
-0x3C,0x51,0xC7,0x06,0x20,0x7A,0x3D,0x51,0xC7,0x06,0x22,0x7A,0x40,0x51,0xC6,0x06,
-0x24,0x7A,0x20,0xC6,0x06,0x25,0x7A,0x20,0xC6,0x06,0x26,0x7A,0x02,0xC3,0xA1,0xF8,
-0x79,0x48,0x74,0x14,0xBE,0xD7,0x79,0xE8,0x3C,0x00,0x8B,0xF8,0xAC,0x3C,0x3A,0x75,
-0x07,0x8E,0xC7,0xE8,0x30,0x00,0x8B,0xF8,0xC3,0x90,0x8B,0xC7,0x2B,0x06,0xFE,0x79,
-0x8A,0xF0,0x24,0x0F,0x8A,0xD0,0x02,0xD0,0x02,0xD0,0x80,0xC2,0x0B,0xC0,0xEE,0x04,
-0x80,0xC6,0x03,0x04,0x3D,0xC3,0x8C,0xC0,0xE8,0x93,0x00,0xB0,0x3A,0xE8,0xE4,0x00,
-0x8B,0xC7,0xE8,0x89,0x00,0xC3,0x51,0x33,0xC9,0x90,0xAC,0x3C,0x20,0x74,0xFB,0x90,
-0x0A,0xC0,0x74,0x26,0x2C,0x30,0x72,0x22,0x3C,0x09,0x76,0x14,0x3C,0x11,0x72,0x1A,
-0x2C,0x07,0x3C,0x0F,0x76,0x0A,0x3C,0x2A,0x72,0x10,0x2C,0x20,0x3C,0x0F,0x77,0x0A,
-0x98,0xC1,0xE1,0x04,0x03,0xC8,0xAC,0xEB,0xD7,0x90,0x4E,0x8B,0xC1,0x59,0xC3,0x90,
-0x06,0x8C,0xC8,0x8E,0xC0,0xE8,0x02,0x00,0x07,0xC3,0x26,0x8A,0x04,0x46,0x0A,0xC0,
-0x74,0x06,0xE8,0x8F,0x00,0xEB,0xF3,0x90,0xC3,0x90,0x0B,0xC0,0x74,0x7A,0x51,0x33,
-0xD2,0xB9,0xE8,0x03,0xF7,0xF1,0x8B,0xCA,0xE8,0x03,0x00,0x8B,0xC1,0x59,0xBA,0x64,
-0x00,0xF6,0xF2,0xE8,0x0C,0x00,0x8A,0xC4,0x98,0xB2,0x0A,0xF6,0xF2,0xE8,0x02,0x00,
-0x8A,0xC4,0x50,0x0A,0xF0,0x74,0x05,0x04,0x30,0xE8,0x58,0x00,0x58,0xC3,0x86,0xC4,
-0xE8,0x07,0x00,0x86,0xC4,0xE8,0x02,0x00,0xC3,0x90,0xC1,0xC8,0x04,0xE8,0x08,0x00,
-0xC1,0xC0,0x04,0xE8,0x02,0x00,0xC3,0x90,0x53,0x50,0x24,0x0F,0xBB,0xAC,0x62,0x2E,
-0xD7,0xE8,0x30,0x00,0x58,0x5B,0xC3,0x90,0x86,0xC4,0xE8,0x07,0x00,0x86,0xC4,0xE8,
-0x02,0x00,0xC3,0x90,0x50,0xB9,0x08,0x00,0x8A,0xE0,0x32,0xC0,0xD1,0xC0,0x04,0x30,
-0xE8,0x11,0x00,0xE2,0xF5,0x58,0xC3,0x90,0xB0,0x30,0xE8,0x07,0x00,0xC3,0xB0,0x20,
-0xE8,0x01,0x00,0xC3,0x56,0x8B,0x36,0xD0,0x79,0x88,0x84,0xD0,0x77,0x46,0x81,0xE6,
-0xFF,0x01,0xFF,0x06,0xD4,0x79,0x89,0x36,0xD0,0x79,0x81,0x3E,0xD4,0x79,0xFE,0x01,
-0x75,0x08,0x56,0xE8,0x14,0x00,0x5E,0xEB,0xF1,0x90,0x5E,0xC3,0xBA,0x02,0x02,0xEC,
-0x24,0x01,0x74,0x04,0xBA,0x06,0x02,0xEC,0xC3,0x90,0x80,0x3E,0xF6,0x79,0x00,0x74,
-0x09,0x60,0xB8,0x01,0x00,0xE8,0x2C,0xEA,0x61,0x90,0xBA,0x02,0x02,0xEC,0xA8,0x04,
-0x74,0x28,0x8B,0x36,0xD2,0x79,0x83,0x3E,0xD4,0x79,0x00,0x74,0x1D,0x8A,0x84,0xD0,
-0x77,0x46,0x81,0xE6,0xFF,0x01,0x89,0x36,0xD2,0x79,0xFF,0x0E,0xD4,0x79,0xBA,0x06,
-0x02,0xEE,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x75,0xDC,0xA1,0xD4,0x79,0xC3,0x52,0xBA,
-0x06,0x02,0xEE,0x5A,0xC3,0x90,0x52,0x50,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x08,
-0x58,0x5A,0xE8,0xE9,0xFF,0xF9,0xC3,0x90,0x58,0x5A,0xF8,0xC3,0x52,0x50,0xBA,0x02,
-0x02,0xEC,0xA8,0x04,0x74,0xFB,0x58,0x5A,0xE8,0xD3,0xFF,0xC3,0x30,0x31,0x32,0x33,
-0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x53,0x50,0x8A,0xE0,
-0x80,0xE4,0x0F,0xBB,0xAC,0x62,0xC0,0xE8,0x04,0x2E,0xD7,0xE8,0xCE,0xFF,0x8A,0xC4,
-0x2E,0xD7,0xE8,0xC7,0xFF,0x58,0x5B,0xC3,0x86,0xE0,0xE8,0xDF,0xFF,0x86,0xE0,0xE8,
-0xDA,0xFF,0xC3,0x90,0xBE,0x94,0x4D,0x50,0x2E,0xAC,0x3C,0x00,0x74,0x05,0xE8,0xAB,
-0xFF,0xEB,0xF5,0x58,0xC3,0x90,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0xBF,
-0x04,0x00,0xC7,0x46,0xFC,0x00,0x00,0xC7,0x46,0xFA,0x00,0x00,0xC7,0x46,0xF8,0x00,
-0x00,0x83,0x7E,0x06,0x00,0x75,0x0E,0x56,0xE8,0xB6,0x0E,0x59,0x0B,0xC0,0x75,0x05,
-0x8B,0xC7,0xE9,0x5B,0x01,0x8B,0x46,0xFC,0x89,0x46,0xFE,0x0B,0xFF,0x75,0x05,0xB8,
-0x01,0x00,0xEB,0x02,0x33,0xC0,0x50,0x56,0xE8,0xA4,0x0D,0x59,0x59,0xB4,0x00,0x89,
-0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xFB,0x08,0x76,0x03,0xE9,0x2B,0x01,0xD1,0xE3,0x2E,
-0xFF,0xA7,0x94,0x64,0xB8,0x03,0x00,0xE9,0x26,0x01,0x83,0x7E,0xFA,0x00,0x74,0x14,
-0xC7,0x46,0xFA,0x00,0x00,0x8A,0x44,0x58,0x98,0x50,0x8A,0x44,0x59,0x98,0x50,0xE8,
-0xC2,0x0F,0x59,0x59,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,
-0xE8,0x9B,0x08,0x59,0x83,0x7E,0x06,0x00,0x75,0x05,0x8B,0xC7,0xE9,0xF1,0x00,0x83,
-0xFF,0x04,0x75,0x03,0xE9,0xE6,0x00,0x8B,0xC7,0xE9,0xE4,0x00,0x83,0x7E,0xFE,0x00,
-0x75,0x03,0xBF,0x02,0x00,0xE9,0xD5,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03,0xBF,0x01,
-0x00,0xE9,0xC9,0x00,0x8B,0x5E,0xFE,0x83,0xFB,0x07,0x76,0x03,0xE9,0x86,0x00,0xD1,
-0xE3,0x2E,0xFF,0xA7,0x84,0x64,0x33,0xFF,0xE9,0x7F,0x00,0xBF,0x04,0x00,0x80,0x7C,
-0x58,0x0F,0x74,0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x44,0x58,0x6A,0x08,0x56,
-0xE8,0x7E,0x0C,0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x72,0x0C,0x59,
-0x59,0xC7,0x46,0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,
-0x00,0x56,0xE8,0x19,0x08,0x59,0xEB,0x42,0xBF,0x04,0x00,0x80,0x7C,0x58,0x00,0x74,
-0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x4C,0x58,0x6A,0x08,0x56,0xE8,0x41,0x0C,
-0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x35,0x0C,0x59,0x59,0xC7,0x46,
-0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8,
-0xDC,0x07,0x59,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xEB,0x31,0xBF,0x04,0x00,0xEB,
-0x2C,0xC7,0x46,0xF8,0x01,0x00,0x6A,0x08,0x56,0xE8,0x05,0x0C,0x59,0x59,0x80,0x7C,
-0x58,0x09,0x7D,0x04,0xB0,0x0F,0xEB,0x02,0xB0,0x00,0x04,0x80,0x50,0x56,0xE8,0xF0,
-0x0B,0x59,0x59,0xBF,0x04,0x00,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xE9,0xA5,0xFE,
-0x5F,0x5E,0xC9,0xC3,0xC6,0x63,0x45,0x64,0x45,0x64,0x45,0x64,0x45,0x64,0xCB,0x63,
-0x08,0x64,0x33,0x64,0x5A,0x63,0x9C,0x63,0xA8,0x63,0x78,0x64,0xB4,0x63,0x4C,0x64,
-0x4C,0x64,0x51,0x64,0x54,0x63,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8B,
-0x7E,0x08,0x6A,0x01,0x56,0xE8,0xA9,0x0B,0x59,0x59,0x8A,0x46,0x06,0xC0,0xE0,0x06,
-0x04,0x80,0x50,0x56,0xE8,0x9A,0x0B,0x59,0x59,0xC7,0x46,0xFE,0x00,0x00,0x89,0x7E,
-0xF8,0xEB,0x03,0xFF,0x46,0xFE,0x8B,0x5E,0xF8,0xFF,0x46,0xF8,0x80,0x3F,0x00,0x75,
-0xF2,0x83,0x7E,0xFE,0x10,0x7D,0x25,0xB8,0x10,0x00,0x2B,0x46,0xFE,0xD1,0xF8,0x89,
-0x46,0xFC,0xC7,0x46,0xFA,0x00,0x00,0xEB,0x0B,0x6A,0x20,0x56,0xE8,0x62,0x0B,0x59,
-0x59,0xFF,0x46,0xFA,0x8B,0x46,0xFA,0x3B,0x46,0xFC,0x7C,0xED,0xEB,0x0C,0x8B,0xDF,
-0x47,0x8A,0x07,0x50,0x56,0xE8,0x49,0x0B,0x59,0x59,0x80,0x3D,0x00,0x75,0xEF,0x6A,
-0x02,0x56,0xE8,0x3C,0x0B,0x59,0x59,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x04,0x00,
-0x00,0x56,0x57,0x8B,0x7E,0x04,0xC7,0x46,0xFE,0x00,0x00,0xBE,0x14,0x00,0xE9,0x09,
-0x01,0x8B,0x5E,0xFE,0x83,0xC3,0x04,0x2B,0xDF,0x8A,0x87,0xAC,0x0B,0x88,0x44,0x5A,
-0xC6,0x44,0x58,0x08,0x8A,0x46,0xFE,0x88,0x44,0x59,0xC7,0x44,0x06,0x00,0x00,0xC6,
-0x44,0x19,0x00,0xC6,0x44,0x1A,0x00,0xC6,0x44,0x1B,0x00,0xC6,0x44,0x1D,0x0D,0xC6,
-0x44,0x1E,0x03,0xC6,0x44,0x1F,0x00,0xC6,0x44,0x20,0x00,0xC6,0x44,0x21,0x00,0xC6,
-0x44,0x5B,0x00,0xC6,0x44,0x5D,0x00,0xC6,0x44,0x5E,0x00,0xC6,0x44,0x5F,0x00,0xC6,
-0x44,0x60,0x00,0xC7,0x46,0xFC,0x00,0x00,0xEB,0x0D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,
-0x40,0x30,0x00,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x10,0x7C,0xED,0xC7,0x46,0xFC,
-0x00,0x00,0xEB,0x0A,0x8B,0x5E,0xFC,0xC6,0x40,0x50,0x00,0xFF,0x46,0xFC,0x83,0x7E,
-0xFC,0x04,0x7C,0xF0,0xC7,0x44,0x54,0x00,0x00,0xC7,0x44,0x56,0x00,0x00,0x8A,0x44,
-0x5A,0x98,0xBA,0xF8,0x00,0x23,0xD0,0xB8,0x05,0x00,0x0B,0xC2,0x89,0x46,0xFC,0x9C,
-0xFA,0x8A,0x46,0xFC,0xBA,0xFE,0x00,0xEE,0xBA,0x00,0x00,0xEC,0x9D,0x24,0x08,0x88,
-0x46,0xFC,0x83,0x7E,0xFC,0x00,0x75,0x02,0xEB,0x4A,0xFF,0x76,0xFE,0xE8,0x7A,0x0C,
-0x59,0x68,0x35,0x02,0x56,0xE8,0x32,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x34,0x68,0x38,
-0x02,0x56,0xE8,0x25,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x27,0x68,0x42,0x02,0x56,0xE8,
-0x18,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x1A,0x68,0x4C,0x02,0x56,0xE8,0x0B,0x0A,0x59,
-0x59,0x0B,0xC0,0x75,0x0D,0x68,0x56,0x02,0x56,0xE8,0xFE,0x09,0x59,0x59,0x0B,0xC0,
-0x74,0x02,0xEB,0x00,0xFF,0x46,0xFE,0x83,0xC6,0x62,0x39,0x7E,0xFE,0x7D,0x03,0xE9,
-0xEF,0xFE,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x46,
-0x04,0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x8B,0xF0,0x83,0x7E,0x06,0x00,0x74,
-0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x08,0x00,0x89,0x44,0x04,0x8A,0x46,0x08,0x88,
-0x44,0x5C,0x56,0xE8,0x59,0x04,0x59,0x8B,0xF8,0x8B,0xC7,0x89,0x44,0x56,0x89,0x44,
-0x54,0x8A,0x44,0x5D,0x88,0x44,0x2F,0x0B,0xFF,0x75,0x1D,0x68,0xC2,0x0F,0x6A,0x01,
-0x56,0xE8,0x02,0xFE,0x83,0xC4,0x06,0xEB,0x00,0x6A,0x01,0x56,0xE8,0x47,0xFC,0x59,
-0x59,0x0B,0xC0,0x75,0xF4,0xBF,0x01,0x00,0x89,0x7E,0xFA,0xB9,0x05,0x00,0xBB,0xCB,
-0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xFA,0x74,0x07,0x43,0x43,0xE2,0xF4,0xE9,0xA4,0x03,
-0x2E,0xFF,0x67,0x0A,0xC7,0x44,0x06,0x02,0x00,0xC7,0x44,0x08,0xF4,0x08,0x8B,0x5E,
-0x04,0xD1,0xE3,0x8B,0x87,0xFC,0x08,0x89,0x44,0x0A,0x33,0xC0,0x8B,0xF8,0x89,0x44,
-0x54,0xE9,0x80,0x03,0x56,0xE8,0xBB,0x05,0x59,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,
-0x44,0x60,0xE9,0x6F,0x03,0x83,0x7C,0x04,0x08,0x75,0x30,0x80,0x7C,0x5C,0x01,0x75,
-0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xE4,0x08,0x56,0xE8,
-0xF7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,
-0xB7,0xC4,0x08,0x56,0xE8,0xE2,0x08,0x59,0x59,0xEB,0x2E,0x80,0x7C,0x5C,0x01,0x75,
-0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xD4,0x08,0x56,0xE8,
-0xC7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,
-0xB7,0xB4,0x08,0x56,0xE8,0xB2,0x08,0x59,0x59,0x6A,0x01,0x56,0xE8,0x87,0xFB,0x59,
-0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x2A,0xD1,0xE3,0x2E,0xFF,0xA7,0xC3,0x6A,0xBF,
-0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5E,0xEB,0x18,0x8A,0x44,0x5D,0x04,0xFF,0x24,
-0x07,0x88,0x44,0x5D,0xEB,0x0C,0x8A,0x44,0x5D,0xFE,0xC0,0x24,0x07,0x88,0x44,0x5D,
-0xEB,0x00,0xE9,0xCF,0x02,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,
-0xFD,0x02,0x56,0xE8,0x63,0x08,0x59,0x59,0x68,0x1D,0x03,0x56,0xE8,0x5A,0x08,0x59,
-0x59,0x6A,0x01,0x56,0xE8,0x2F,0xFB,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x36,
-0xD1,0xE3,0x2E,0xFF,0xA7,0xBB,0x6A,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5F,
-0xEB,0x24,0x8A,0x44,0x5D,0x04,0xFF,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88,
-0x44,0x5D,0xEB,0x12,0x8A,0x44,0x5D,0xFE,0xC0,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,
-0xC2,0x88,0x44,0x5D,0xEB,0x00,0xE9,0x6B,0x02,0x8B,0x5C,0x06,0x83,0xC3,0xFE,0xD1,
-0xE3,0x8B,0x40,0x08,0x89,0x04,0x8B,0x1C,0xFF,0x77,0x06,0x6A,0x00,0x56,0xE8,0x85,
-0xFC,0x83,0xC4,0x06,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x40,0x08,0x89,0x44,0x02,
-0x8B,0x5C,0x02,0xFF,0x77,0x06,0x6A,0x01,0x56,0xE8,0x6A,0xFC,0x83,0xC4,0x06,0x6A,
-0x01,0x56,0xE8,0xB1,0xFA,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x76,0x03,0xE9,0x1F,
-0x02,0xD1,0xE3,0x2E,0xFF,0xA7,0xB3,0x6A,0x8B,0x5C,0x02,0x8B,0x47,0x04,0x89,0x44,
-0x02,0x8B,0x5C,0x02,0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,
-0x00,0x3B,0x44,0x04,0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,
-0x44,0x02,0x89,0x47,0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,
-0x08,0xE9,0xDE,0x01,0x8B,0x5C,0x02,0x8B,0x47,0x02,0x89,0x44,0x02,0x8B,0x5C,0x02,
-0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B,0x44,0x04,
-0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02,0x89,0x47,
-0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9,0xA2,0x01,
-0xBF,0x01,0x00,0xE9,0x9C,0x01,0x8B,0x5C,0x02,0x8A,0x07,0xB4,0x00,0x89,0x46,0xF8,
-0xB9,0x0C,0x00,0xBB,0x83,0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xF8,0x74,0x07,0x43,0x43,
-0xE2,0xF4,0xE9,0x77,0x01,0x2E,0xFF,0x67,0x18,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x5C,
-0x02,0x03,0xD8,0x8B,0x47,0x08,0x8B,0x5C,0x06,0xFF,0x44,0x06,0xD1,0xE3,0x89,0x40,
-0x08,0x8B,0x1C,0x80,0x7F,0x01,0x00,0x74,0x12,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,
-0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x40,0x01,0xFF,0x4C,
-0x06,0xE9,0x3A,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,
-0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x25,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,
-0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xFF,0x4C,0x06,0xE9,0x0D,
-0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,
-0x30,0x40,0x18,0xE9,0xF8,0x00,0xB8,0xF0,0x10,0x8B,0xF8,0x89,0x44,0x54,0x8A,0x44,
-0x5F,0x88,0x44,0x5D,0xE9,0xE7,0x00,0x8A,0x44,0x1C,0x98,0x3D,0x02,0x00,0x74,0x07,
-0x3D,0x03,0x00,0x74,0x02,0xEB,0x07,0xC7,0x46,0xFE,0x00,0x00,0xEB,0x2B,0x8A,0x44,
-0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x69,0x02,0x56,0xE8,0x6B,0x06,0x59,0x59,
-0x6A,0x01,0x56,0xE8,0x40,0xF9,0x59,0x59,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x00,0x74,
-0x06,0x83,0x7E,0xFE,0x03,0x75,0xE9,0xEB,0x00,0x83,0x7E,0xFE,0x03,0x74,0x62,0x8A,
-0x44,0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x6D,0x02,0x56,0xE8,0x3A,0x06,0x59,
-0x59,0x56,0xE8,0x6B,0x97,0x59,0x89,0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xEB,0xFE,0x83,
-0xFB,0x03,0x77,0x33,0xD1,0xE3,0x2E,0xFF,0xA7,0x7B,0x6A,0x68,0xAC,0x02,0x56,0xE8,
-0x17,0x06,0x59,0x59,0xEB,0x23,0x68,0x8F,0x02,0x56,0xE8,0x0C,0x06,0x59,0x59,0xEB,
-0x18,0x68,0x75,0x02,0x56,0xE8,0x01,0x06,0x59,0x59,0xEB,0x0D,0x68,0xC6,0x02,0x56,
-0xE8,0xF6,0x05,0x59,0x59,0xEB,0x02,0xEB,0x00,0x6A,0x01,0x56,0xE8,0xC7,0xF8,0x59,
-0x59,0xBF,0x01,0x00,0xEB,0x38,0x68,0xDD,0x02,0x56,0xE8,0xDC,0x05,0x59,0x59,0x6A,
-0x01,0x56,0xE8,0xB1,0xF8,0x59,0x59,0xBF,0x01,0x00,0xEB,0x22,0xB8,0xD0,0x30,0x8B,
-0xF8,0x89,0x44,0x54,0x8A,0x44,0x60,0x88,0x44,0x5D,0xEB,0x12,0xB8,0xE0,0x20,0x8B,
-0xF8,0x89,0x44,0x54,0x8A,0x44,0x5E,0x88,0x44,0x5D,0xEB,0x02,0xEB,0x00,0xEB,0x02,
-0xEB,0x00,0xEB,0x00,0xE9,0x41,0xFC,0x5F,0x5E,0xC9,0xC3,0xFB,0x69,0x06,0x6A,0x11,
-0x6A,0x1C,0x6A,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x41,0x00,0x42,0x00,0x43,
-0x00,0x44,0x00,0x80,0x00,0x81,0x00,0x82,0x00,0xFF,0x00,0xF9,0x68,0x36,0x6A,0x5C,
-0x6A,0x87,0x69,0x34,0x69,0x76,0x69,0x4C,0x6A,0x49,0x69,0x34,0x69,0x61,0x69,0x49,
-0x69,0x2E,0x69,0xD6,0x68,0x58,0x68,0x94,0x68,0xD0,0x68,0xD7,0x67,0xE2,0x67,0xF4,
-0x67,0xD7,0x67,0x7F,0x67,0x8A,0x67,0x96,0x67,0x7F,0x67,0x00,0x00,0x01,0x00,0xF0,
-0x10,0xE0,0x20,0xD0,0x30,0x09,0x68,0xD4,0x66,0xA5,0x67,0x05,0x67,0xF4,0x66,0xC8,
-0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8A,0x44,0x59,0x98,0x89,0x46,0xFC,0x6A,
-0x09,0x8B,0x46,0xFC,0x05,0x84,0x01,0x50,0xE8,0x93,0x08,0x59,0x59,0x8B,0xF8,0x8B,
-0xC7,0x25,0x00,0xF0,0x3D,0x00,0x10,0x75,0x55,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xF0,
-0x00,0x75,0x4B,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,
-0x04,0x3B,0x46,0xFE,0x7D,0x05,0x33,0xC0,0xE9,0xEF,0x00,0x8B,0xC7,0x25,0x0F,0x00,
-0xBA,0x0F,0x00,0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xE9,0xDB,0x00,0xC7,
-0x44,0x02,0x04,0x09,0x8A,0x46,0xFE,0x88,0x44,0x5F,0x88,0x44,0x5D,0x8B,0x5E,0xFC,
-0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x04,0x09,0xB8,0xF0,0x10,0xE9,0xBC,0x00,0x8B,0xC7,
-0x25,0x00,0xF0,0x3D,0x00,0x20,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xE0,0x00,
-0x75,0x48,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x83,0x7E,0xFE,
-0x08,0x7E,0x05,0x33,0xC0,0xE9,0x92,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,
-0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xEB,0x7F,0x90,0xC7,0x44,0x02,0x0C,
-0x09,0x8A,0x46,0xFE,0x88,0x44,0x5E,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,
-0x87,0xFC,0x08,0x0C,0x09,0xB8,0xE0,0x20,0xEB,0x60,0x8B,0xC7,0x25,0x00,0xF0,0x3D,
-0x00,0x30,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xD0,0x00,0x75,0x48,0x8B,0xC7,
-0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B,0x46,0xFE,0x7D,
-0x04,0x33,0xC0,0xEB,0x35,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0,0x3B,
-0x56,0xFE,0x74,0x04,0x33,0xC0,0xEB,0x22,0xC7,0x44,0x02,0x14,0x09,0x8A,0x46,0xFE,
-0x88,0x44,0x60,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x14,
-0x09,0xB8,0xD0,0x30,0xEB,0x04,0x33,0xC0,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x06,
-0x00,0x00,0x56,0x8B,0x76,0x04,0x6A,0x08,0x56,0xE8,0x35,0x04,0x59,0x59,0x8A,0x44,
-0x58,0x04,0x80,0x50,0x56,0xE8,0x29,0x04,0x59,0x59,0x8B,0x44,0x54,0x3B,0x44,0x56,
-0x75,0x0A,0x8A,0x44,0x5D,0x3A,0x44,0x2F,0x75,0x02,0xEB,0x64,0x8B,0x44,0x54,0x89,
-0x44,0x56,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x88,0x44,0x2F,0x8A,0x44,0x5D,0xB4,0x00,
-0xC1,0xE0,0x08,0x8B,0x54,0x54,0x0B,0xD0,0x8A,0x44,0x5D,0xB4,0x00,0xBB,0x0F,0x00,
-0x2B,0xD8,0x0B,0xD3,0x89,0x56,0xFE,0x6A,0x10,0x8A,0x44,0x59,0x98,0x05,0x04,0x00,
-0x99,0x05,0x40,0x01,0x83,0xD2,0x00,0x52,0x50,0xE8,0x54,0x08,0x83,0xC4,0x06,0x89,
-0x56,0xFC,0x89,0x46,0xFA,0x8B,0x46,0xFE,0x09,0x46,0xFA,0x83,0x4E,0xFC,0x00,0x6A,
-0x19,0xFF,0x76,0xFC,0xFF,0x76,0xFA,0xE8,0x73,0x07,0x83,0xC4,0x06,0xE8,0xFE,0x07,
-0x5E,0xC9,0xC3,0xC8,0x1C,0x00,0x00,0x56,0x57,0x8B,0x5E,0x04,0x8A,0x47,0x59,0x98,
-0x8B,0xF0,0x8B,0x5E,0x04,0x8A,0x47,0x5D,0xB4,0x00,0x89,0x46,0xE6,0x83,0x7E,0xE6,
-0x00,0x7D,0x0A,0x8B,0x5E,0x04,0x8B,0x47,0x04,0x48,0x89,0x46,0xE6,0x8B,0x5E,0x04,
-0x8B,0x47,0x04,0x3B,0x46,0xE6,0x7F,0x05,0xC7,0x46,0xE6,0x00,0x00,0x8B,0x5E,0x04,
-0x8A,0x46,0xE6,0x88,0x47,0x5D,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,
-0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x03,0x30,0x8B,0xDE,
-0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,
-0x61,0x02,0xC6,0x47,0x03,0x30,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,
-0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,
-0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,
-0x33,0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,
-0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,
-0x59,0x02,0x88,0x57,0x02,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,
-0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,
-0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33,
-0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB,
-0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,
-0x02,0x88,0x57,0x02,0x8B,0x5E,0xE6,0xD1,0xE3,0xFF,0xB7,0x12,0x02,0x6A,0x00,0xFF,
-0x76,0x04,0xE8,0xD1,0xF6,0x83,0xC4,0x06,0x68,0xD3,0x0F,0x6A,0x01,0xFF,0x76,0x04,
-0xE8,0xC3,0xF6,0x83,0xC4,0x06,0xFF,0x76,0xE6,0x56,0xE8,0x1F,0x93,0x59,0x59,0x89,
-0x56,0xF2,0x89,0x46,0xF0,0xFF,0x76,0xE6,0x56,0xE8,0x32,0x93,0x59,0x59,0x89,0x56,
-0xEE,0x89,0x46,0xEC,0x9C,0xFA,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89,0x46,0xEA,0xC4,
-0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D,
-0xC7,0x46,0xE4,0x01,0x00,0xE8,0x08,0xA1,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,
-0x46,0xFC,0x2B,0x46,0xFE,0x3D,0xE8,0x03,0x73,0x03,0xE9,0x80,0x01,0x9C,0xFA,0xBA,
-0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC,0x2B,0x46,0xFE,0x89,0x46,0xF8,0xC4,
-0x5E,0xF0,0x26,0x8B,0x07,0x2B,0x46,0xEA,0x89,0x46,0xF6,0xC4,0x5E,0xF0,0x26,0x8B,
-0x07,0x89,0x46,0xEA,0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x2B,0x46,0xE8,0x89,0x46,0xF4,
-0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,
-0x9D,0x81,0x7E,0xF8,0xE8,0x03,0x76,0x1C,0xFF,0x76,0xF8,0xFF,0x76,0xF6,0xE8,0x76,
-0x01,0x59,0x59,0x89,0x46,0xF6,0xFF,0x76,0xF8,0xFF,0x76,0xF4,0xE8,0x68,0x01,0x59,
-0x59,0x89,0x46,0xF4,0xBF,0x0E,0x00,0xEB,0x17,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,
-0x02,0xC6,0x01,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x01,0x20,0x47,
-0x83,0xFF,0x11,0x76,0xE4,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x0D,
-0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x0D,0x30,0x83,0x7E,0xF6,
-0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF6,0x63,0x77,0x05,0xB8,0x0E,
-0x00,0xEB,0x1B,0x81,0x7E,0xF6,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,
-0x7E,0xF6,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,
-0xEB,0x25,0x8B,0x46,0xF6,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,
-0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF6,
-0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF6,0x83,0x7E,0xF6,0x00,0x75,0xD5,0x83,0x7E,0xF4,
-0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF4,0x63,0x77,0x05,0xB8,0x0E,
-0x00,0xEB,0x1B,0x81,0x7E,0xF4,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,
-0x7E,0xF4,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,
-0xEB,0x25,0x8B,0x46,0xF4,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,
-0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF4,
-0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF4,0x83,0x7E,0xF4,0x00,0x75,0xD5,0x8B,0xDE,0xD1,
-0xE3,0xFF,0xB7,0x59,0x02,0xFF,0x76,0x04,0xE8,0x6E,0x00,0x59,0x59,0x8B,0xDE,0xD1,
-0xE3,0xFF,0xB7,0x61,0x02,0xFF,0x76,0x04,0xE8,0x5E,0x00,0x59,0x59,0x6A,0x00,0xFF,
-0x76,0x04,0xE8,0x31,0xF3,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x1F,0xD1,0xE3,
-0x2E,0xFF,0xA7,0xFD,0x6F,0xEB,0x22,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x4E,0xE6,0xEB,
-0x0C,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x46,0xE6,0xEB,0x02,0xEB,0x00,0x83,0x7E,0xE4,
-0x00,0x74,0x03,0xE9,0x2A,0xFE,0xE9,0xD4,0xFC,0x5F,0x5E,0xC9,0xC3,0xD5,0x6F,0xD7,
-0x6F,0xE1,0x6F,0xD5,0x6F,0xEB,0x6F,0x55,0x8B,0xEC,0x8B,0x46,0x04,0xB9,0xE8,0x03,
-0xF7,0xE1,0x8B,0x4E,0x06,0xF7,0xF1,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06,
-0xEB,0x0E,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x33,0x00,0x59,0x59,
-0x80,0x3C,0x00,0x75,0xED,0xEB,0x00,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,
-0x06,0xEB,0x14,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x45,0x00,0x59,
-0x59,0x0B,0xC0,0x74,0x02,0xEB,0x07,0x80,0x3C,0x00,0x75,0xE7,0xEB,0x00,0x5E,0x5D,
-0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,
-0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,
-0x06,0x9D,0xE8,0xAB,0x9E,0xEB,0xE9,0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0xEB,
-0x00,0x5E,0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,
-0x89,0x46,0xFE,0xE8,0x00,0xA2,0x89,0x46,0xFC,0xE8,0xFA,0xA1,0x2B,0x46,0xFC,0x3D,
-0xB8,0x0B,0x76,0x05,0xB8,0x01,0x00,0xEB,0x23,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,
-0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D,0xE8,0x62,0x9E,0xEB,0xD9,
-0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0x33,0xC0,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,
-0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x83,0x7E,0x06,0x00,0x74,0x07,0x56,0xE8,
-0x03,0x01,0x59,0xEB,0x05,0x56,0xE8,0xA2,0x00,0x59,0x88,0x46,0xFF,0x80,0x7E,0xFF,
-0x08,0x77,0x06,0x8A,0x46,0xFF,0xE9,0x84,0x00,0x80,0x7E,0xFF,0x0F,0x76,0x03,0xEB,
-0x79,0x90,0x8A,0x46,0xFF,0xB4,0x00,0x2D,0x0A,0x00,0x8B,0xD8,0x83,0xFB,0x04,0x77,
-0x67,0xD1,0xE3,0x2E,0xFF,0xA7,0x91,0x71,0xB0,0x00,0xEB,0x61,0x56,0xE8,0x6B,0x00,
-0x59,0xB4,0x00,0x25,0x0F,0x00,0x89,0x46,0xFC,0x56,0xE8,0x5E,0x00,0x59,0xB4,0x00,
-0x8B,0xF8,0x56,0xE8,0x55,0x00,0x59,0xB4,0x00,0xC1,0xE0,0x08,0x8B,0xD7,0x03,0xD0,
-0x8B,0xFA,0x8B,0x5E,0xFC,0xD1,0xE3,0x89,0x78,0x30,0xEB,0x2E,0x56,0xE8,0x3B,0x00,
-0x59,0x88,0x44,0x5B,0xEB,0x24,0x56,0xE8,0x31,0x00,0x59,0x88,0x44,0x50,0x56,0xE8,
-0x29,0x00,0x59,0x88,0x44,0x51,0x56,0xE8,0x21,0x00,0x59,0x88,0x44,0x52,0x56,0xE8,
-0x19,0x00,0x59,0x88,0x44,0x53,0xEB,0x02,0xEB,0x00,0xE9,0x5B,0xFF,0x5F,0x5E,0xC9,
-0xC3,0x28,0x71,0x88,0x71,0x2C,0x71,0x5C,0x71,0x66,0x71,0xC8,0x04,0x00,0x00,0x56,
-0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,
-0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x71,0x9D,0xEB,
-0xE9,0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,
-0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,
-0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0x32,0xE4,0x24,
-0x01,0x9D,0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,
-0x98,0x89,0x46,0xFE,0xE8,0x9F,0xA0,0x89,0x46,0xFA,0xE8,0x99,0xA0,0x2B,0x46,0xFA,
-0x3D,0xB8,0x0B,0x76,0x04,0xB0,0x08,0xEB,0x24,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,
-0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x02,0x9D,0xEB,0xDA,
-0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3,
-0x55,0x8B,0xEC,0x56,0x8B,0x56,0x04,0x8A,0x46,0x06,0xEE,0x33,0xF6,0xEB,0x03,0x50,
-0x58,0x46,0x83,0xFE,0x14,0x7C,0xF8,0x5E,0x5D,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,
-0x56,0x04,0xEC,0x88,0x46,0xFF,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46,0x83,0xFE,0x14,
-0x7C,0xF8,0x8A,0x46,0xFF,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x57,
-0x8B,0x76,0x04,0x83,0x3E,0xB0,0x0B,0x00,0x75,0x1F,0xBA,0x88,0x01,0xB0,0x00,0xEE,
-0xBA,0x86,0x01,0xB0,0x00,0xEE,0x6A,0x09,0x6A,0x00,0x68,0x30,0x01,0xE8,0x7D,0x01,
-0x83,0xC4,0x06,0xC7,0x06,0xB0,0x0B,0x01,0x00,0x6A,0x09,0x8B,0xC6,0x05,0x80,0x01,
-0x50,0xE8,0xDA,0x00,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0xC1,0xE8,0x0C,0x25,0x0F,0x00,
-0x89,0x46,0xFE,0x8B,0xC7,0xC1,0xE8,0x08,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2,
-0x0C,0x3B,0xC2,0x75,0x21,0x8B,0xC7,0xC1,0xE8,0x04,0x25,0x0F,0x00,0x8B,0x56,0xFE,
-0x83,0xF2,0x06,0x3B,0xC2,0x75,0x0F,0x8B,0xC7,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,
-0xF2,0x09,0x3B,0xC2,0x74,0x0D,0x6A,0x07,0x56,0xE8,0x38,0x00,0x59,0x59,0xC7,0x46,
-0xFE,0x07,0x00,0x8A,0x46,0xFE,0x04,0x80,0xA2,0x33,0x02,0x8B,0xC6,0xBA,0x62,0x00,
-0xF7,0xEA,0x8A,0x56,0xFE,0x8B,0xD8,0x88,0x97,0x6C,0x00,0x68,0x32,0x02,0x8B,0xC6,
-0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x50,0xE8,0x0E,0xFD,0x59,0x59,0xEB,0x00,
-0x5F,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x06,0x83,0xE6,0x0F,0x8B,
-0xC6,0xC1,0xE0,0x0C,0x8B,0xD6,0x83,0xF2,0x0C,0xC1,0xE2,0x08,0x0B,0xC2,0x8B,0xD6,
-0x83,0xF2,0x06,0xC1,0xE2,0x04,0x0B,0xC2,0x8B,0xD6,0x83,0xF2,0x09,0x0B,0xC2,0x89,
-0x46,0xFE,0x6A,0x19,0x6A,0x10,0x8B,0x46,0x04,0x99,0x05,0x40,0x01,0x83,0xD2,0x00,
-0x52,0x50,0xE8,0x6B,0x01,0x83,0xC4,0x06,0x0B,0x46,0xFE,0x83,0xCA,0x00,0x52,0x50,
-0xE8,0x9A,0x00,0x83,0xC4,0x06,0xE8,0x25,0x01,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B,
-0xEC,0x56,0x57,0x33,0xFF,0x6A,0x01,0x68,0x86,0x01,0xE8,0xA3,0xFE,0x59,0x59,0xB1,
-0x10,0x2A,0x4E,0x06,0xD3,0x66,0x04,0x33,0xF6,0xEB,0x2E,0x81,0x7E,0x04,0x00,0x80,
-0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68,0x88,0x01,0xE8,0x81,0xFE,0x59,
-0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0x77,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,
-0xE8,0x6D,0xFE,0x59,0x59,0xD1,0x66,0x04,0x46,0x3B,0x76,0x06,0x7C,0xCD,0x33,0xF6,
-0xEB,0x24,0xD1,0xE7,0x6A,0x03,0x68,0x86,0x01,0xE8,0x54,0xFE,0x59,0x59,0x6A,0x01,
-0x68,0x86,0x01,0xE8,0x4A,0xFE,0x59,0x59,0x68,0x88,0x01,0xE8,0x5C,0xFE,0x59,0x98,
-0x25,0x01,0x00,0x0B,0xF8,0x46,0x83,0xFE,0x10,0x7C,0xD7,0x6A,0x00,0x68,0x86,0x01,
-0xE8,0x2D,0xFE,0x59,0x59,0x8B,0xC7,0xEB,0x00,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,
-0x56,0x57,0x8B,0x7E,0x08,0x6A,0x01,0x68,0x86,0x01,0xE8,0x13,0xFE,0x59,0x59,0xB8,
-0x20,0x00,0x2B,0xC7,0x50,0xFF,0x76,0x06,0xFF,0x76,0x04,0xE8,0xA2,0x00,0x83,0xC4,
-0x06,0x89,0x56,0x06,0x89,0x46,0x04,0x33,0xF6,0xEB,0x47,0x81,0x7E,0x06,0x00,0x80,
-0x72,0x0C,0x75,0x06,0x83,0x7E,0x04,0x00,0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,
-0x50,0x68,0x88,0x01,0xE8,0xD9,0xFD,0x59,0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0xCF,
-0xFD,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0xC5,0xFD,0x59,0x59,0x6A,0x01,0xFF,
-0x76,0x06,0xFF,0x76,0x04,0xE8,0x58,0x00,0x83,0xC4,0x06,0x89,0x56,0x06,0x89,0x46,
-0x04,0x46,0x3B,0xF7,0x7C,0xB5,0x6A,0x00,0x68,0x86,0x01,0xE8,0xA2,0xFD,0x59,0x59,
-0x6A,0x00,0x68,0x86,0x01,0xE8,0x98,0xFD,0x59,0x59,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,
-0xEC,0x56,0x6A,0x01,0x68,0x86,0x01,0xE8,0x86,0xFD,0x59,0x59,0x33,0xF6,0xEB,0x00,
-0x68,0x88,0x01,0xE8,0x94,0xFD,0x59,0xA8,0x01,0x75,0x08,0x8B,0xC6,0x46,0x3D,0x64,
-0x00,0x7C,0xED,0x6A,0x00,0x68,0x86,0x01,0xE8,0x65,0xFD,0x59,0x59,0x5E,0x5D,0xC3,
-0xC8,0x04,0x00,0x00,0x8B,0x46,0x04,0x8B,0x56,0x06,0x8B,0x4E,0x08,0xE3,0x06,0xD1,
-0xE0,0xD1,0xD2,0xE2,0xFA,0x89,0x46,0xFC,0x89,0x56,0xFE,0x8B,0x56,0xFE,0x8B,0x46,
-0xFC,0xEB,0x00,0xC9,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x60,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0x04,0xFF,0xB8,0x00,0x80,0xBA,
+0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1B,
+0x9C,0x0E,0xE8,0x87,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0xBA,
+0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xBA,0x08,0x01,0xEC,0xA2,0x8C,0x12,0xA8,0x40,
+0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,0x00,0xE8,0x12,0xFE,
+0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0xB6,0xFE,0xB8,0x00,0x80,0xBA,0x22,0xFF,
+0xEF,0x07,0x1F,0x61,0xCF,0x90,0xEE,0x86,0xE0,0xEE,0x86,0xE0,0xEC,0x86,0xE0,0xEC,
+0x86,0xE0,0x80,0xE1,0xFE,0xF3,0x6C,0x90,0x80,0xE1,0xFE,0xF3,0x6E,0x90,0x05,0x00,
+0x75,0x47,0xA8,0x4B,0x05,0x00,0x75,0x48,0xA8,0x4B,0x05,0x00,0xA3,0x48,0xA8,0x4B,
+0x05,0x00,0x35,0x49,0xA8,0x4B,0x06,0x00,0x98,0x48,0x96,0x4B,0x06,0x00,0xBA,0x48,
+0x96,0x4B,0x06,0x00,0xC3,0x48,0x96,0x4B,0x06,0x00,0xCB,0x48,0x96,0x4B,0x06,0x00,
+0x20,0x49,0x96,0x4B,0x06,0x00,0x28,0x49,0x96,0x4B,0x06,0x00,0x4E,0x4A,0x9C,0x4B,
+0x06,0x00,0x7B,0x4A,0x9C,0x4B,0x05,0x00,0x9E,0x4A,0xA2,0x4B,0x05,0x00,0xEC,0x4A,
+0xA2,0x4B,0x00,0x00,0x1E,0x06,0x83,0x3E,0x44,0x12,0x00,0x74,0x09,0xA0,0x06,0x01,
+0x24,0x30,0x3C,0x30,0x74,0x1A,0x8C,0xC8,0x8E,0xD8,0x8E,0xC0,0xBB,0xAE,0x4B,0x8B,
+0x0F,0xE3,0x0D,0x8B,0x7F,0x02,0x8B,0x77,0x04,0xF3,0xA4,0x83,0xC3,0x06,0xEB,0xEF,
+0x07,0x1F,0xC3,0x90,0x33,0xC0,0xA3,0x3E,0x01,0xB9,0x0C,0x01,0xBE,0x40,0x01,0x8B,
+0xFE,0x81,0xC6,0xB4,0x0F,0x89,0x04,0x8B,0xC6,0x2B,0xF1,0x3B,0xC7,0x77,0xF6,0xA3,
+0x3C,0x01,0xC3,0x90,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x8B,0x5E,0x00,0x3B,
+0xEB,0x74,0x2B,0x8B,0x76,0x02,0x89,0x1C,0x89,0x77,0x02,0x36,0xA1,0x3C,0x01,0x89,
+0x46,0x00,0x36,0x89,0x2E,0x3C,0x01,0x8B,0xEB,0xFF,0x4E,0x06,0x74,0x08,0x8B,0x6E,
+0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07,
+0x1F,0xC3,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x98,0x89,0x46,0x06,0x89,0x66,
+0x04,0x3B,0x6E,0x00,0x74,0x10,0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89,
+0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07,0x1F,0xC3,0xC3,0x90,0x1E,0x06,0x60,0x9C,
+0xFA,0x33,0xED,0x8E,0xDD,0x8B,0x2E,0x3C,0x01,0x85,0xED,0x74,0x3D,0x8B,0x4E,0x00,
+0x89,0x0E,0x3C,0x01,0x8B,0xCC,0x8D,0xA6,0x0A,0x01,0x56,0x1E,0x06,0x60,0x89,0x66,
+0x04,0xC7,0x46,0x08,0x0F,0x1A,0xC7,0x46,0x06,0x01,0x00,0x8B,0x1E,0x3E,0x01,0x85,
+0xDB,0x74,0x1D,0x8B,0xC5,0x87,0x07,0x89,0x46,0x00,0x89,0x5E,0x02,0x8B,0xD8,0x89,
+0x6F,0x02,0x8B,0xE1,0x9D,0x61,0x07,0x1F,0xF8,0xC3,0x9D,0x61,0x07,0x1F,0xF9,0xC3,
+0x89,0x2E,0x3E,0x01,0x89,0x6E,0x00,0x89,0x6E,0x02,0x87,0xE1,0x9D,0x8B,0xE1,0xEB,
+0xE4,0x00,0x0D,0x0A,0x54,0x65,0x72,0x6D,0x69,0x6E,0x61,0x6C,0x73,0x20,0x73,0x75,
+0x70,0x70,0x6F,0x72,0x74,0x65,0x64,0x3A,0x0D,0x0A,0x31,0x29,0x20,0x41,0x4E,0x53,
+0x49,0x20,0x63,0x6F,0x6D,0x70,0x61,0x74,0x69,0x62,0x6C,0x65,0x0D,0x0A,0x32,0x29,
+0x20,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x0D,0x0A,0x50,0x6C,0x65,0x61,0x73,0x65,
+0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x3A,0x20,0x00,0x0D,0x0A,0x63,0x6F,0x64,0x65,
+0x20,0x73,0x65,0x67,0x6D,0x65,0x6E,0x74,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E,0x69,
+0x74,0x6F,0x72,0x20,0x76,0x32,0x2E,0x35,0x0A,0x0D,0x0A,0x3E,0x00,0x0D,0x0A,0x50,
+0x61,0x72,0x64,0x6F,0x6E,0x3F,0x00,0x0D,0x0A,0x4E,0x6F,0x20,0x61,0x64,0x64,0x72,
+0x65,0x73,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x00,0x0D,0x0A,
+0x3A,0x00,0x0D,0x0A,0x00,0x4C,0x6F,0x63,0x3D,0x00,0x0D,0x0A,0x46,0x41,0x54,0x41,
+0x4C,0x20,0x45,0x52,0x52,0x4F,0x52,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E,0x69,0x74,
+0x6F,0x72,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x73,0x3A,0x2D,0x0D,0x0A,0x20,
+0x20,0x20,0x44,0x2C,0x64,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,
+0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,
+0x0D,0x0A,0x20,0x20,0x20,0x4C,0x2C,0x6C,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,
+0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x73,0x69,0x6E,
+0x67,0x6C,0x65,0x20,0x6C,0x69,0x6E,0x65,0x0D,0x0A,0x20,0x20,0x20,0x45,0x2C,0x65,
+0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,
+0x65,0x64,0x69,0x74,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x0D,0x0A,0x20,0x20,0x20,
+0x46,0x2C,0x66,0x5B,0x5B,0x78,0x78,0x78,0x78,0x20,0x5D,0x78,0x78,0x78,0x78,0x5D,
+0x20,0x2D,0x20,0x66,0x69,0x6C,0x6C,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x20,0x70,
+0x61,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x0D,0x0A,0x20,0x20,0x20,0x49,0x5B,
+0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,
+0x20,0x77,0x6F,0x72,0x64,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,
+0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x69,0x5B,0x78,0x78,0x78,0x78,
+0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x79,0x74,
+0x65,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,0x70,0x6F,0x72,
+0x74,0x0D,0x0A,0x20,0x20,0x20,0x4F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20,
+0x77,0x6F,0x72,0x64,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,
+0x20,0x6F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20,0x62,0x79,0x74,0x65,0x20,
+0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x47,0x5B,0x5B,0x78,
+0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x2D,0x20,0x67,
+0x6F,0x74,0x6F,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x0D,0x0A,0x20,0x20,0x20,
+0x57,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,
+0x20,0x2D,0x20,0x77,0x61,0x74,0x63,0x68,0x20,0x61,0x20,0x77,0x6F,0x72,0x64,0x0D,
+0x0A,0x20,0x20,0x20,0x43,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74,0x65,0x72,0x72,0x75,0x70,0x74,
+0x73,0x20,0x6F,0x66,0x66,0x0D,0x0A,0x20,0x20,0x20,0x53,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74,
+0x65,0x72,0x72,0x75,0x70,0x74,0x73,0x20,0x6F,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x73,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x2D,0x20,0x73,0x69,0x6E,0x67,0x6C,0x65,0x20,0x73,0x74,0x65,0x70,0x0D,0x0A,0x20,
+0x20,0x20,0x42,0x78,0x78,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x20,
+0x73,0x65,0x74,0x0D,0x0A,0x20,0x20,0x20,0x62,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B,
+0x70,0x6F,0x69,0x6E,0x74,0x20,0x63,0x6C,0x65,0x61,0x72,0x0D,0x0A,0x20,0x20,0x20,
+0x52,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x2D,0x20,0x72,0x65,0x73,0x74,0x61,0x72,0x74,0x20,0x62,0x72,0x65,0x61,0x6B,
+0x70,0x6F,0x69,0x6E,0x74,0x0D,0x0A,0x20,0x20,0x20,0x72,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x72,0x65,0x67,
+0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x61,0x74,0x20,0x62,0x72,0x6B,0x70,0x74,0x0D,
+0x0A,0x20,0x20,0x20,0x58,0x2C,0x78,0x20,0x6E,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x65,0x78,0x61,0x6D,0x69,0x6E,0x65,0x20,0x63,
+0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x48,0x2C,0x3F,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,
+0x74,0x68,0x69,0x73,0x20,0x6D,0x65,0x73,0x73,0x61,0x67,0x65,0x00,0x1B,0x5B,0x32,
+0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x41,0x4E,0x53,0x49,0x20,0x54,0x65,0x72,0x6D,
+0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x0A,0x00,0x1B,0x5B,0x4B,0x00,0x1B,0x5B,0x4A,0x00,
+0x1B,0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x00,0x1B,0x5B,0x44,0x20,0x1B,
+0x5B,0x44,0x00,0x1B,0x5B,0x31,0x3B,0x37,0x32,0x48,0x00,0x1B,0x5B,0x00,0x3B,0x00,
+0x48,0x00,0x1B,0x5B,0x73,0x00,0x1B,0x5B,0x75,0x00,0x1B,0x7A,0x2B,0x0B,0x7F,0x1B,
+0x7A,0x2E,0x0C,0x7F,0x1B,0x7A,0x2D,0x08,0x7F,0x1B,0x7A,0x2C,0x0A,0x7F,0x1B,0x7A,
+0x22,0x08,0x7F,0x1A,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x20,0x54,0x65,0x72,0x6D,
+0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x00,0x1B,0x54,0x00,0x1B,0x59,0x00,0x1A,0x00,0x1E,
+0x00,0x08,0x20,0x08,0x00,0x00,0x1B,0x3D,0x00,0x00,0x00,0x1B,0x46,0x00,0x0D,0x00,
+0x3F,0x44,0x64,0x45,0x65,0x46,0x66,0x47,0x67,0x48,0x68,0x49,0x69,0x4F,0x6F,0x43,
+0x63,0x53,0x73,0x42,0x62,0x52,0x72,0x57,0x77,0x58,0x78,0x4C,0x6C,0x3C,0x60,0xD4,
+0x57,0xD4,0x57,0x50,0x58,0x50,0x58,0xD6,0x59,0xD6,0x59,0xB4,0x59,0xB4,0x59,0x3C,
+0x60,0x3C,0x60,0x6C,0x57,0x48,0x57,0x26,0x57,0x06,0x57,0x90,0x57,0x90,0x57,0x98,
+0x57,0x48,0x5F,0x0C,0x5F,0x58,0x5F,0x33,0x5F,0x40,0x5F,0xA0,0x57,0xA0,0x57,0xFE,
+0x59,0xFE,0x59,0xDC,0x57,0xDC,0x57,0x88,0x61,0x98,0x61,0xC0,0x61,0xCC,0x61,0xD8,
+0x61,0xF6,0x61,0x02,0x62,0x22,0x62,0xF8,0x56,0x4A,0x62,0x58,0x62,0x60,0x59,0x20,
+0x20,0x66,0x6C,0x61,0x67,0x73,0x3D,0x00,0x20,0x20,0x61,0x78,0x3D,0x00,0x20,0x20,
+0x62,0x78,0x3D,0x00,0x20,0x20,0x63,0x78,0x3D,0x00,0x20,0x20,0x64,0x78,0x3D,0x00,
+0x20,0x20,0x63,0x73,0x3D,0x00,0x20,0x20,0x64,0x73,0x3D,0x00,0x20,0x20,0x65,0x73,
+0x3D,0x00,0x20,0x20,0x73,0x73,0x3D,0x00,0x20,0x20,0x64,0x69,0x3D,0x00,0x20,0x20,
+0x73,0x69,0x3D,0x00,0x20,0x20,0x62,0x70,0x3D,0x00,0x20,0x20,0x73,0x70,0x3D,0x00,
+0x20,0x20,0x69,0x70,0x3D,0x00,0x20,0x63,0x68,0x61,0x6E,0x65,0x6C,0x3D,0x00,0x20,
+0x20,0x20,0x20,0x73,0x65,0x67,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x72,0x3D,
+0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F,0x6D,0x61,
+0x78,0x3D,0x00,0x20,0x74,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F,
+0x73,0x69,0x7A,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x74,
+0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x74,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00,
+0x20,0x74,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x70,0x63,0x6E,
+0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,
+0x74,0x66,0x3D,0x00,0x20,0x72,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x69,
+0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20,
+0x72,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x6D,0x69,0x6E,0x3D,
+0x00,0x20,0x72,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x6F,
+0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x68,0x72,0x3D,0x00,0x20,0x74,0x68,0x5F,
+0x73,0x74,0x66,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x74,
+0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x69,0x7A,0x3D,0x00,
+0x20,0x74,0x68,0x5F,0x74,0x72,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x66,0x6C,0x67,
+0x3D,0x00,0x20,0x74,0x68,0x5F,0x63,0x6E,0x74,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,
+0x74,0x72,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x72,0x68,
+0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20,
+0x72,0x68,0x5F,0x73,0x70,0x61,0x3D,0x00,0x20,0x72,0x68,0x5F,0x61,0x73,0x6F,0x3D,
+0x00,0x20,0x72,0x68,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,0x66,0x6C,
+0x67,0x3D,0x00,0x20,0x6D,0x5F,0x63,0x61,0x72,0x65,0x3D,0x00,0x20,0x70,0x74,0x5F,
+0x66,0x6C,0x6F,0x3D,0x00,0x20,0x61,0x73,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x72,
+0x6D,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F,0x69,0x6E,0x3D,0x00,
+0x20,0x20,0x71,0x5F,0x6F,0x75,0x74,0x3D,0x00,0x20,0x71,0x5F,0x64,0x72,0x61,0x6E,
+0x3D,0x00,0x20,0x20,0x71,0x5F,0x74,0x69,0x6D,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F,
+0x66,0x63,0x3D,0x00,0x20,0x71,0x5F,0x73,0x74,0x61,0x74,0x3D,0x00,0x20,0x71,0x5F,
+0x64,0x61,0x74,0x61,0x3D,0x00,0x20,0x71,0x5F,0x6D,0x6F,0x64,0x6D,0x3D,0x00,0x20,
+0x68,0x61,0x6E,0x64,0x5F,0x6F,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x62,0x3D,
+0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x65,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,
+0x69,0x3D,0x00,0x20,0x20,0x6F,0x70,0x6F,0x73,0x74,0x3D,0x00,0x20,0x20,0x74,0x69,
+0x6D,0x65,0x6F,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x31,0x3D,0x00,0x20,0x63,
+0x75,0x73,0x74,0x6D,0x32,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x64,0x3D,0x00,
+0x20,0x74,0x78,0x72,0x61,0x74,0x65,0x3D,0x00,0x20,0x72,0x78,0x72,0x61,0x74,0x65,
+0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x61,0x70,0x3D,0x00,0x20,0x63,0x5F,0x61,0x64,
+0x64,0x72,0x3D,0x00,0x20,0x63,0x5F,0x61,0x69,0x73,0x72,0x3D,0x00,0x20,0x63,0x5F,
+0x78,0x74,0x61,0x67,0x3D,0x00,0x20,0x63,0x5F,0x64,0x65,0x66,0x72,0x3D,0x00,0x20,
+0x63,0x5F,0x66,0x6C,0x73,0x68,0x3D,0x00,0x20,0x74,0x78,0x6D,0x61,0x78,0x73,0x3D,
+0x00,0x20,0x72,0x69,0x5F,0x65,0x6D,0x73,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6C,0x73,
+0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x65,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,
+0x66,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x63,0x72,0x3D,0x00,0x20,0x20,
+0x63,0x5F,0x6C,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x64,0x73,0x73,0x3D,0x00,
+0x20,0x63,0x5F,0x64,0x73,0x73,0x69,0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,0x73,0x72,
+0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x63,
+0x61,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x65,0x66,0x72,0x3D,0x00,0x20,0x63,0x5F,
+0x65,0x72,0x73,0x74,0x3D,0x00,0x20,0x63,0x5F,0x65,0x63,0x6E,0x74,0x3D,0x00,0x20,
+0x63,0x5F,0x62,0x72,0x6B,0x63,0x3D,0x00,0x20,0x63,0x5F,0x62,0x6F,0x6B,0x63,0x3D,
+0x00,0x20,0x63,0x5F,0x72,0x65,0x70,0x6C,0x3D,0x00,0x20,0x63,0x5F,0x63,0x63,0x73,
+0x72,0x3D,0x00,0x20,0x63,0x5F,0x73,0x74,0x74,0x31,0x3D,0x00,0x20,0x63,0x5F,0x73,
+0x74,0x74,0x32,0x3D,0x00,0x2B,0xC0,0x8E,0xD8,0x8E,0xC0,0xE8,0xC2,0x00,0xE8,0xE5,
+0x00,0xFA,0xBF,0x84,0x00,0xC7,0x05,0xDC,0x56,0x8C,0x4D,0x02,0xBF,0x0C,0x00,0xC7,
+0x05,0x6E,0x5E,0x8C,0x4D,0x02,0xBF,0x04,0x00,0xC7,0x05,0xBA,0x5E,0x8C,0x4D,0x02,
+0xE8,0xF1,0x00,0x90,0xE8,0x49,0x01,0xE8,0x16,0x00,0xF4,0x90,0xE8,0xE5,0x00,0xBE,
+0xBA,0x4D,0xE8,0x09,0x0C,0xA0,0x93,0x12,0xE8,0x5D,0x0C,0xE8,0xC2,0x09,0xEB,0xE4,
+0xE8,0xD5,0x0C,0xE8,0xC4,0x0C,0x0A,0xC0,0x74,0xF6,0x8B,0x1E,0xF8,0x79,0x3C,0x0D,
+0x74,0x2E,0x3C,0x08,0x74,0x17,0x3C,0x7F,0x74,0x13,0x83,0xFB,0x20,0x7F,0xE1,0x88,
+0x87,0xD6,0x79,0x43,0x89,0x1E,0xF8,0x79,0xE8,0x77,0x0C,0xEB,0xD3,0x0B,0xDB,0x74,
+0xCF,0x4B,0x89,0x1E,0xF8,0x79,0x8B,0x36,0x16,0x7A,0xE8,0xC1,0x0B,0xEB,0xC1,0x90,
+0xE8,0x02,0x00,0xEB,0xBB,0xC6,0x87,0xD6,0x79,0x00,0x0B,0xDB,0x74,0x1E,0xA0,0xD6,
+0x79,0xBF,0x60,0x51,0xB9,0x1D,0x00,0x8B,0xD9,0x06,0x0E,0x07,0xF2,0xAE,0x07,0x75,
+0x17,0x41,0x2B,0xD9,0xD1,0xE3,0x2E,0xFF,0x97,0x7D,0x51,0x90,0x33,0xC0,0xA3,0xF8,
+0x79,0xBE,0x89,0x4D,0xE8,0x87,0x0B,0xC3,0xBE,0x8D,0x4D,0xE8,0x80,0x0B,0xEB,0xEC,
+0xBA,0x00,0x02,0xB0,0x93,0xEE,0xB0,0x55,0xEE,0xBA,0x10,0x02,0xB0,0x93,0xEE,0xB0,
+0xAA,0xEE,0xBA,0x00,0x02,0xEC,0x3C,0x55,0x75,0x08,0xBA,0x10,0x02,0xEC,0x3C,0xAA,
+0x74,0x03,0xE8,0x2F,0xF6,0xC3,0xBA,0x04,0x02,0xB0,0x1A,0xEE,0xB0,0x20,0xEE,0xB0,
+0x30,0xEE,0xB0,0x40,0xEE,0xB0,0x80,0xEE,0xBA,0x00,0x02,0xB0,0x13,0xEE,0xB0,0x07,
+0xEE,0xBA,0x08,0x02,0xB0,0x80,0xEE,0xBA,0x02,0x02,0xB0,0xBB,0xEE,0xBA,0x04,0x02,
+0xB0,0x05,0xEE,0xC3,0xC6,0x06,0xCA,0x13,0x01,0xC7,0x06,0xF8,0x79,0x00,0x00,0xC6,
+0x06,0xF6,0x79,0x01,0xC7,0x06,0xD0,0x79,0x00,0x00,0xC7,0x06,0xD2,0x79,0x00,0x00,
+0xC7,0x06,0xD4,0x79,0x00,0x00,0xC7,0x06,0xFA,0x79,0x00,0x00,0xC7,0x06,0xFC,0x79,
+0x00,0x00,0xC7,0x06,0xFE,0x79,0x00,0x00,0xC7,0x06,0x00,0x7A,0x00,0x00,0xC7,0x06,
+0x02,0x7A,0xCE,0x59,0x8C,0x0E,0x04,0x7A,0xC7,0x06,0x06,0x7A,0x00,0x00,0xC7,0x06,
+0x27,0x7A,0x00,0x00,0xC6,0x06,0x29,0x7A,0x00,0xC6,0x06,0x2A,0x7A,0x00,0xC3,0x90,
+0xBE,0x22,0x4D,0xE8,0xC8,0x0A,0xE8,0x3F,0x00,0x2C,0x31,0x3C,0x01,0x77,0xF7,0xE8,
+0x81,0x09,0x8B,0x36,0x0C,0x7A,0xE8,0xB5,0x0A,0xBE,0x6A,0x4D,0xE8,0xAF,0x0A,0x0E,
+0x58,0xE8,0xF8,0x0A,0xBE,0x7A,0x4D,0xE8,0xA4,0x0A,0xC3,0x90,0x60,0xD1,0xE3,0x83,
+0xFB,0x18,0x73,0x11,0x1E,0xBA,0x00,0x00,0x8E,0xDA,0x2E,0xFF,0x97,0xB7,0x51,0x8B,
+0xEC,0x89,0x46,0x10,0x1F,0x61,0xCF,0x90,0xE8,0x4F,0x0B,0x0A,0xC0,0x75,0x05,0xE8,
+0x56,0x0B,0xEB,0xF4,0xC3,0x90,0x83,0x3E,0xF8,0x79,0x01,0x74,0x16,0xBE,0xD7,0x79,
+0xE8,0x31,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x04,0x3C,0x20,0x75,0x05,0xE8,0x23,
+0x0A,0xEE,0xC3,0xE9,0xD2,0xFE,0x83,0x3E,0xF8,0x79,0x01,0x74,0xF6,0xBE,0xD7,0x79,
+0xE8,0x11,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x08,0x3C,0x20,0x74,0x04,0xE9,0xB7,
+0xFE,0x90,0xE8,0xFF,0x09,0xEF,0xC3,0x90,0x8B,0x16,0x06,0x7A,0x83,0x3E,0xF8,0x79,
+0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xEB,0x09,0x8B,0xD0,0xA3,0x06,0x7A,0xB0,0x20,
+0xE8,0x57,0x0B,0x8B,0x16,0x06,0x7A,0xEC,0xE8,0x6F,0x0B,0xC3,0x8B,0x16,0x06,0x7A,
+0x83,0x3E,0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xC7,0x09,0x8B,0xD0,0xA3,
+0x06,0x7A,0xB0,0x20,0xE8,0x33,0x0B,0x8B,0x16,0x06,0x7A,0xED,0xE8,0x67,0x0B,0xC3,
+0xFA,0xC6,0x06,0xF6,0x79,0x00,0xC3,0x90,0xC6,0x06,0xF6,0x79,0x01,0xFB,0xC3,0x90,
+0x06,0xE8,0x58,0x09,0xB0,0x20,0xE8,0x11,0x0B,0x26,0x8B,0x05,0xE8,0x47,0x0B,0xB0,
+0x08,0xE8,0x06,0x0B,0xE8,0x03,0x0B,0xE8,0x00,0x0B,0xE8,0xFD,0x0A,0xB8,0x01,0x00,
+0xE8,0xCF,0xF4,0xBA,0x02,0x02,0xEC,0x24,0x01,0x75,0x02,0xEB,0xDC,0xBA,0x06,0x02,
+0xEC,0x07,0xC3,0x90,0xC7,0x06,0x08,0x7A,0x10,0x00,0xEB,0x06,0xC7,0x06,0x08,0x7A,
+0x01,0x00,0x06,0x8E,0x06,0xFC,0x79,0x8B,0x3E,0xFA,0x79,0xE8,0x0E,0x09,0xE8,0x0B,
+0x00,0x89,0x3E,0xFA,0x79,0x8C,0x06,0xFC,0x79,0x07,0xC3,0x90,0xBE,0xB2,0x4D,0xE8,
+0x7C,0x09,0x8B,0x16,0x08,0x7A,0x52,0xE8,0x2A,0x09,0xE8,0x0F,0x0A,0xE8,0x0C,0x0A,
+0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A,0x01,0xE8,0xBC,0x09,0xE8,0xFD,0x09,0x43,
+0xE2,0xF4,0xE8,0xF7,0x09,0xE8,0xF4,0x09,0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A,
+0x01,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xE3,0x09,0x43,
+0xE2,0xEC,0xBE,0xB2,0x4D,0xE8,0x36,0x09,0x83,0xC7,0x10,0x5A,0x4A,0x75,0xB7,0xC3,
+0x06,0x8E,0x06,0x00,0x7A,0x8B,0x3E,0xFE,0x79,0xE8,0xA0,0x08,0x89,0x3E,0xFE,0x79,
+0x8C,0x06,0x00,0x7A,0x57,0x8B,0x36,0x0E,0x7A,0xE8,0x12,0x09,0xC7,0x06,0x08,0x7A,
+0x10,0x00,0xBA,0x00,0x02,0xE8,0xE8,0x00,0xE8,0x81,0xFF,0x5F,0xBA,0x00,0x00,0xE8,
+0xDE,0x00,0xBE,0xB5,0x4D,0xE8,0xF6,0x08,0x8C,0xC0,0xE8,0x3F,0x09,0xB0,0x3A,0xE8,
+0x90,0x09,0x8B,0xC7,0xE8,0x35,0x09,0xE8,0x7E,0x08,0xE8,0xC3,0x00,0x90,0xE8,0xB7,
+0x09,0xE8,0xA6,0x09,0x0A,0xC0,0x74,0xF6,0x3C,0x0B,0x75,0x06,0x83,0xEF,0x10,0xEB,
+0x19,0x90,0x3C,0x0A,0x75,0x06,0x83,0xC7,0x10,0xEB,0x0F,0x90,0x3C,0x0C,0x75,0x04,
+0x47,0xEB,0x07,0x90,0x3C,0x08,0x75,0x24,0x4F,0x90,0x8B,0x36,0xFE,0x79,0x8B,0xC7,
+0x2B,0xC6,0x3D,0x00,0x01,0x72,0xA5,0x3D,0x10,0x01,0x72,0x04,0x83,0xEE,0x20,0x90,
+0x83,0xC6,0x10,0x89,0x36,0xFE,0x79,0x57,0x8B,0xFE,0xEB,0x80,0x3C,0x2E,0x75,0x08,
+0xBA,0x01,0x13,0xE8,0x6A,0x00,0x07,0xC3,0xC6,0x06,0x0A,0x7A,0x02,0x32,0xC9,0x90,
+0x3C,0x30,0x72,0x4C,0x3C,0x39,0x76,0x0C,0x24,0x5F,0x3C,0x41,0x72,0x42,0x3C,0x46,
+0x77,0x3E,0x2C,0x07,0x2C,0x30,0x50,0xE8,0xCC,0x08,0x58,0x02,0xC8,0xFE,0x0E,0x0A,
+0x7A,0x74,0x0F,0xC0,0xE1,0x04,0xE8,0x2F,0x09,0xE8,0x1E,0x09,0x0A,0xC0,0x74,0xF6,
+0xEB,0xCE,0x26,0x88,0x0D,0xE8,0xE0,0x07,0x8A,0xD0,0xE8,0x23,0x00,0x8A,0xC1,0x3C,
+0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xD5,0x08,0xE9,0x70,0xFF,
+0xE8,0xC5,0x07,0xE8,0x0A,0x00,0x26,0x8A,0x05,0xE8,0x7C,0x08,0xE9,0x1D,0xFF,0x90,
+0xF6,0x06,0x26,0x7A,0x02,0x75,0x02,0x86,0xF2,0x52,0x8B,0x36,0x1A,0x7A,0xE8,0x0D,
+0x08,0x5A,0x52,0x8A,0xC6,0x02,0x06,0x24,0x7A,0xF6,0x06,0x26,0x7A,0x01,0x75,0x06,
+0xE8,0x9F,0x08,0xEB,0x0D,0x90,0x32,0xE4,0xE8,0x0D,0x08,0x8B,0x36,0x1C,0x7A,0xE8,
+0xEC,0x07,0x5A,0x8A,0xC2,0x02,0x06,0x25,0x7A,0xF6,0x06,0x26,0x7A,0x01,0x75,0x06,
+0xE8,0x7F,0x08,0xEB,0x06,0x90,0x32,0xE4,0xE8,0xED,0x07,0x8B,0x36,0x1E,0x7A,0xE8,
+0xCC,0x07,0xC3,0x90,0x06,0x8E,0x06,0x04,0x7A,0x8B,0x3E,0x02,0x7A,0xE8,0x3C,0x07,
+0x89,0x3E,0x02,0x7A,0x8C,0x06,0x04,0x7A,0x07,0xFF,0x1E,0x02,0x7A,0xC3,0xBE,0x97,
+0x4D,0xE8,0xAA,0x07,0xCB,0x90,0x06,0x57,0xBE,0xD7,0x79,0xE8,0x66,0x07,0x8B,0xD8,
+0xE8,0x61,0x07,0x8B,0xC8,0x2B,0xCB,0x78,0x11,0x8E,0xC3,0xBF,0x00,0x00,0xB8,0xFF,
+0xFF,0x51,0xB9,0x08,0x00,0xF3,0xAB,0x59,0xE2,0xF7,0x5F,0x07,0xC3,0x90,0x06,0xBE,
+0xD7,0x79,0xE8,0x3F,0x07,0x8B,0xD8,0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00,0xBE,0x26,
+0x52,0xE8,0xF1,0x08,0x8B,0xC3,0xE8,0xDD,0x08,0xB8,0x01,0x00,0xE8,0x73,0xF2,0xE8,
+0xE0,0x08,0xBE,0x2F,0x52,0xE8,0xDD,0x08,0x8B,0x47,0x18,0xE8,0xC8,0x08,0xBE,0x77,
+0x52,0xE8,0xD1,0x08,0x8B,0x47,0x26,0xE8,0xBC,0x08,0xBE,0x53,0x52,0xE8,0xC5,0x08,
+0x8B,0x47,0x1E,0xE8,0xB0,0x08,0xBE,0x5C,0x52,0xE8,0xB9,0x08,0x8B,0x47,0x20,0xE8,
+0xA4,0x08,0xBE,0x6E,0x52,0xE8,0xAD,0x08,0x8B,0x47,0x24,0xE8,0x98,0x08,0xBE,0x80,
+0x52,0xE8,0xA1,0x08,0x8B,0x47,0x2A,0xE8,0x8C,0x08,0xE8,0x95,0x08,0xBE,0x38,0x52,
+0xE8,0x92,0x08,0x8B,0x07,0xE8,0x7E,0x08,0xBE,0x41,0x52,0xE8,0x87,0x08,0x8B,0x47,
+0x1A,0xE8,0x72,0x08,0xBE,0x4A,0x52,0xE8,0x7B,0x08,0x8B,0x47,0x1C,0xE8,0x66,0x08,
+0xBE,0x65,0x52,0xE8,0x6F,0x08,0x8B,0x47,0x22,0xE8,0x5A,0x08,0xE8,0x63,0x08,0xBE,
+0xD1,0x52,0xE8,0x60,0x08,0x8B,0x47,0x38,0xE8,0x4B,0x08,0xBE,0xAD,0x52,0xE8,0x54,
+0x08,0x8B,0x47,0x30,0xE8,0x3F,0x08,0xBE,0xB6,0x52,0xE8,0x48,0x08,0x8B,0x47,0x32,
+0xE8,0x33,0x08,0xBE,0xA4,0x52,0xE8,0x3C,0x08,0x8B,0x47,0x2E,0xE8,0x27,0x08,0xBE,
+0xBF,0x52,0xE8,0x30,0x08,0x8B,0x47,0x34,0xE8,0x1B,0x08,0xE8,0x24,0x08,0xBE,0x89,
+0x52,0xE8,0x21,0x08,0x8B,0x47,0x04,0xE8,0x0C,0x08,0xBE,0x92,0x52,0xE8,0x15,0x08,
+0x8B,0x47,0x14,0xE8,0x00,0x08,0xBE,0x9B,0x52,0xE8,0x09,0x08,0x8B,0x47,0x2C,0xE8,
+0xF4,0x07,0xBE,0xC8,0x52,0xE8,0xFD,0x07,0x8B,0x47,0x36,0xE8,0xE8,0x07,0xBE,0xDA,
+0x52,0xE8,0xF1,0x07,0x8B,0x47,0x3A,0xE8,0xDC,0x07,0xBE,0xE3,0x52,0xE8,0xE5,0x07,
+0x8B,0x47,0x3C,0xE8,0xD0,0x07,0xE8,0xD9,0x07,0xBE,0x19,0x53,0xE8,0xD6,0x07,0x8B,
+0x47,0x48,0xE8,0xC1,0x07,0xBE,0xFE,0x52,0xE8,0xCA,0x07,0x8B,0x47,0x42,0xE8,0xB5,
+0x07,0xBE,0x07,0x53,0xE8,0xBE,0x07,0x8B,0x47,0x44,0xE8,0xA9,0x07,0xBE,0x7C,0x53,
+0xE8,0xB2,0x07,0x8B,0x47,0x4C,0xE8,0x9D,0x07,0xBE,0x85,0x53,0xE8,0xA6,0x07,0x8B,
+0x47,0x4E,0xE8,0x91,0x07,0xBE,0x8E,0x53,0xE8,0x9A,0x07,0x8B,0x47,0x50,0xE8,0x85,
+0x07,0xE8,0x8E,0x07,0xBE,0x22,0x53,0xE8,0x8B,0x07,0x8B,0x47,0x4A,0xE8,0x76,0x07,
+0xBE,0xEC,0x52,0xE8,0x7F,0x07,0x8B,0x47,0x08,0xE8,0x6A,0x07,0xBE,0xF5,0x52,0xE8,
+0x73,0x07,0x8B,0x47,0x40,0xE8,0x5E,0x07,0xBE,0x10,0x53,0xE8,0x67,0x07,0x8B,0x47,
+0x46,0xE8,0x52,0x07,0xE8,0x5B,0x07,0xBE,0x6A,0x53,0xE8,0x58,0x07,0x8B,0x47,0x7A,
+0xE8,0x43,0x07,0xBE,0x3D,0x53,0xE8,0x4C,0x07,0x8B,0x47,0x70,0xE8,0x37,0x07,0xBE,
+0x46,0x53,0xE8,0x40,0x07,0x8B,0x47,0x72,0xE8,0x2B,0x07,0xBE,0x4F,0x53,0xE8,0x34,
+0x07,0x8B,0x47,0x74,0xE8,0x1F,0x07,0xE8,0x28,0x07,0xBE,0x2B,0x53,0xE8,0x25,0x07,
+0x8B,0x47,0x0C,0xE8,0x10,0x07,0xBE,0x34,0x53,0xE8,0x19,0x07,0x8B,0x47,0x10,0xE8,
+0x04,0x07,0xBE,0x58,0x53,0xE8,0x0D,0x07,0x8B,0x47,0x76,0xE8,0xF8,0x06,0xBE,0x61,
+0x53,0xE8,0x01,0x07,0x8B,0x47,0x78,0xE8,0xEC,0x06,0xBE,0x73,0x53,0xE8,0xF5,0x06,
+0x8B,0x47,0x3E,0xE8,0xE0,0x06,0xE8,0xE9,0x06,0xBE,0x97,0x53,0xE8,0xE6,0x06,0x8B,
+0x47,0x52,0xE8,0xD1,0x06,0xBE,0xA0,0x53,0xE8,0xDA,0x06,0x8B,0x47,0x54,0xE8,0xC5,
+0x06,0xBE,0xA9,0x53,0xE8,0xCE,0x06,0x8B,0x47,0x56,0xE8,0xB9,0x06,0xBE,0xB2,0x53,
+0xE8,0xC2,0x06,0x8B,0x47,0x58,0xE8,0xAD,0x06,0xBE,0xBB,0x53,0xE8,0xB6,0x06,0x8B,
+0x47,0x5A,0xE8,0xA1,0x06,0xBE,0xC4,0x53,0xE8,0xAA,0x06,0x8B,0x47,0x5C,0xE8,0x95,
+0x06,0xE8,0x9E,0x06,0xBE,0xCD,0x53,0xE8,0x9B,0x06,0x8B,0x47,0x5E,0xE8,0x86,0x06,
+0xBE,0xD6,0x53,0xE8,0x8F,0x06,0x8B,0x47,0x60,0xE8,0x7A,0x06,0xBE,0xDF,0x53,0xE8,
+0x83,0x06,0x8B,0x47,0x62,0xE8,0x6E,0x06,0xBE,0xE8,0x53,0xE8,0x77,0x06,0x8B,0x47,
+0x7C,0xE8,0x62,0x06,0xBE,0xF1,0x53,0xE8,0x6B,0x06,0x8B,0x47,0x7E,0xE8,0x56,0x06,
+0xBE,0xFA,0x53,0xE8,0x5F,0x06,0x8B,0x87,0x80,0x00,0xE8,0x49,0x06,0xE8,0x52,0x06,
+0xBE,0x42,0x54,0xE8,0x4F,0x06,0x8B,0x87,0x9E,0x00,0xE8,0x39,0x06,0xBE,0x03,0x54,
+0xE8,0x42,0x06,0x8B,0x47,0x64,0xE8,0x2D,0x06,0xBE,0x0C,0x54,0xE8,0x36,0x06,0x8B,
+0x47,0x6E,0xE8,0x21,0x06,0xBE,0x15,0x54,0xE8,0x2A,0x06,0x8B,0x87,0x8E,0x00,0xE8,
+0x14,0x06,0xBE,0x1E,0x54,0xE8,0x1D,0x06,0x8B,0x87,0x90,0x00,0xE8,0x07,0x06,0xBE,
+0x27,0x54,0xE8,0x10,0x06,0x8B,0x87,0x92,0x00,0xE8,0xFA,0x05,0xE8,0x03,0x06,0xBE,
+0x30,0x54,0xE8,0x00,0x06,0x8B,0x87,0x94,0x00,0xE8,0xEA,0x05,0xBE,0x39,0x54,0xE8,
+0xF3,0x05,0x8B,0x87,0x96,0x00,0xE8,0xDD,0x05,0xBE,0x6F,0x54,0xE8,0xE6,0x05,0x8B,
+0x87,0x98,0x00,0xE8,0xD0,0x05,0xBE,0x5D,0x54,0xE8,0xD9,0x05,0x8A,0x87,0xA0,0x00,
+0xE8,0xA7,0x05,0xBE,0x54,0x54,0xE8,0xCC,0x05,0x8A,0x47,0x28,0xE8,0x9B,0x05,0xBE,
+0x66,0x54,0xE8,0xC0,0x05,0x8A,0x87,0xA1,0x00,0xE8,0x8E,0x05,0xE8,0xB3,0x05,0xBE,
+0x78,0x54,0xE8,0xB0,0x05,0x8A,0x87,0xA2,0x00,0xE8,0x7E,0x05,0xBE,0x81,0x54,0xE8,
+0xA3,0x05,0x8A,0x87,0xA3,0x00,0xE8,0x71,0x05,0xBE,0x8A,0x54,0xE8,0x96,0x05,0x8A,
+0x87,0xA4,0x00,0xE8,0x64,0x05,0xBE,0x93,0x54,0xE8,0x89,0x05,0x8A,0x87,0xA5,0x00,
+0xE8,0x57,0x05,0xBE,0x9C,0x54,0xE8,0x7C,0x05,0x8A,0x87,0xA6,0x00,0xE8,0x4A,0x05,
+0xBE,0xA5,0x54,0xE8,0x6F,0x05,0x8A,0x87,0xA7,0x00,0xE8,0x3D,0x05,0xBE,0xAE,0x54,
+0xE8,0x62,0x05,0x8A,0x87,0xA8,0x00,0xE8,0x30,0x05,0xE8,0x55,0x05,0xBE,0xB7,0x54,
+0xE8,0x52,0x05,0x8A,0x87,0xA9,0x00,0xE8,0x20,0x05,0xBE,0xC0,0x54,0xE8,0x45,0x05,
+0x8A,0x87,0xAA,0x00,0xE8,0x13,0x05,0xBE,0xC9,0x54,0xE8,0x38,0x05,0x8A,0x87,0xAB,
+0x00,0xE8,0x06,0x05,0xBE,0xD2,0x54,0xE8,0x2B,0x05,0x8A,0x87,0xAD,0x00,0xE8,0xF9,
+0x04,0xBE,0xDB,0x54,0xE8,0x1E,0x05,0x8A,0x87,0xAE,0x00,0xE8,0xEC,0x04,0xBE,0xE4,
+0x54,0xE8,0x11,0x05,0x8A,0x87,0xAF,0x00,0xE8,0xDF,0x04,0xBE,0xED,0x54,0xE8,0x04,
+0x05,0x8A,0x87,0xB0,0x00,0xE8,0xD2,0x04,0xE8,0xF7,0x04,0xBE,0xF6,0x54,0xE8,0xF4,
+0x04,0x8A,0x87,0xB1,0x00,0xE8,0xC2,0x04,0xBE,0xFF,0x54,0xE8,0xE7,0x04,0x8A,0x87,
+0xB2,0x00,0xE8,0xB5,0x04,0xBE,0x08,0x55,0xE8,0xDA,0x04,0x8A,0x87,0xB3,0x00,0xE8,
+0xA8,0x04,0xBE,0x11,0x55,0xE8,0xCD,0x04,0x8A,0x87,0xBB,0x00,0xE8,0x9B,0x04,0xE8,
+0xC0,0x04,0xBE,0x1A,0x55,0xE8,0xBD,0x04,0x8A,0x87,0xBC,0x00,0xE8,0x8B,0x04,0xBE,
+0x23,0x55,0xE8,0xB0,0x04,0x8A,0x87,0xBE,0x00,0xE8,0x7E,0x04,0xBE,0x2C,0x55,0xE8,
+0xA3,0x04,0x8A,0x87,0xBF,0x00,0xE8,0x71,0x04,0xE8,0x96,0x04,0x07,0xC3,0x60,0x06,
+0x1E,0x16,0x8B,0xEC,0xFF,0x4E,0x16,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8,
+0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89,0x2E,0x2D,0x7A,0xE8,0xCB,0x00,0x81,0x66,0x1A,
+0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0xD8,0x00,0xB8,0x00,0x5F,0xA3,0x2B,0x7A,
+0xE8,0x5D,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A,0x81,0x4E,0x1A,0x00,0x01,0xC6,
+0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90,0x60,0x06,0x1E,0x16,0x8B,0xEC,
+0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89,
+0x2E,0x2D,0x7A,0x81,0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0x92,0x00,
+0xB8,0x00,0x5F,0xA3,0x2B,0x7A,0xE8,0x17,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A,
+0x81,0x4E,0x1A,0x00,0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90,
+0xB8,0xF0,0x00,0xE8,0x8C,0xED,0xFF,0x26,0x2B,0x7A,0xC3,0x90,0x06,0x53,0x56,0x80,
+0x3E,0x29,0x7A,0x00,0x74,0x03,0xE8,0x3F,0x00,0xBE,0xD7,0x79,0xE8,0x25,0x02,0x8B,
+0xD8,0xA3,0x27,0x7A,0x2E,0x8A,0x07,0xA2,0x29,0x7A,0xB0,0xCC,0x2E,0x88,0x07,0x5E,
+0x5B,0x07,0xC3,0xC6,0x06,0x2A,0x7A,0x00,0xB8,0x0A,0x5F,0xA3,0x2B,0x7A,0xC3,0x90,
+0x8B,0x2E,0x2D,0x7A,0xE8,0x2B,0x00,0xC3,0xC6,0x06,0x2A,0x7A,0x01,0xE8,0x08,0x00,
+0xB8,0x0A,0x5F,0xA3,0x2B,0x7A,0xC3,0x90,0x57,0x80,0x3E,0x29,0x7A,0x00,0x74,0x0F,
+0x8B,0x3E,0x27,0x7A,0xA0,0x29,0x7A,0x2E,0x88,0x05,0xC6,0x06,0x29,0x7A,0x00,0x5F,
+0xC3,0x90,0xBE,0xB2,0x4D,0xE8,0x06,0x02,0xBE,0xD8,0x51,0xE8,0x00,0x02,0xFF,0x76,
+0x14,0x58,0xE8,0x47,0x02,0xBE,0xDE,0x51,0xE8,0xF3,0x01,0xFF,0x76,0x0E,0x58,0xE8,
+0x3A,0x02,0xBE,0xE4,0x51,0xE8,0xE6,0x01,0xFF,0x76,0x12,0x58,0xE8,0x2D,0x02,0xBE,
+0xEA,0x51,0xE8,0xD9,0x01,0xFF,0x76,0x10,0x58,0xE8,0x20,0x02,0xBE,0x14,0x52,0xE8,
+0xCC,0x01,0xFF,0x76,0x0A,0x58,0xE8,0x13,0x02,0xBE,0x1A,0x52,0xE8,0xBF,0x01,0xFF,
+0x76,0x0C,0x58,0xE8,0x06,0x02,0xBE,0xCF,0x51,0xE8,0xB2,0x01,0xFF,0x76,0x1A,0x58,
+0xE8,0xF9,0x01,0xBE,0xB2,0x4D,0xE8,0xA5,0x01,0xBE,0xF0,0x51,0xE8,0x9F,0x01,0xFF,
+0x76,0x18,0x58,0xE8,0xE6,0x01,0xBE,0xF6,0x51,0xE8,0x92,0x01,0xFF,0x76,0x02,0x58,
+0xE8,0xD9,0x01,0xBE,0xFC,0x51,0xE8,0x85,0x01,0xFF,0x76,0x04,0x58,0xE8,0xCC,0x01,
+0xBE,0x02,0x52,0xE8,0x78,0x01,0xFF,0x76,0x00,0x58,0xE8,0xBF,0x01,0xBE,0x08,0x52,
+0xE8,0x6B,0x01,0xFF,0x76,0x06,0x58,0xE8,0xB2,0x01,0xBE,0x0E,0x52,0xE8,0x5E,0x01,
+0xFF,0x76,0x08,0x58,0xE8,0xA5,0x01,0xBE,0x20,0x52,0xE8,0x51,0x01,0xFF,0x76,0x16,
+0x58,0xE8,0x98,0x01,0xBE,0x89,0x4D,0xE8,0x44,0x01,0xC3,0x90,0xBE,0xC9,0x4D,0xE8,
+0x3C,0x01,0xC3,0x3C,0x00,0x74,0x05,0x3C,0x01,0x74,0x59,0xC3,0xC7,0x06,0x0C,0x7A,
+0xCD,0x50,0xC7,0x06,0x0E,0x7A,0xF0,0x50,0xC7,0x06,0x10,0x7A,0xE8,0x50,0xC7,0x06,
+0x12,0x7A,0xEC,0x50,0xC7,0x06,0x14,0x7A,0xF4,0x50,0xC7,0x06,0x16,0x7A,0xFB,0x50,
+0xC7,0x06,0x18,0x7A,0x03,0x51,0xC7,0x06,0x1A,0x7A,0x0B,0x51,0xC7,0x06,0x1C,0x7A,
+0x0E,0x51,0xC7,0x06,0x1E,0x7A,0x10,0x51,0xC7,0x06,0x20,0x7A,0x12,0x51,0xC7,0x06,
+0x22,0x7A,0x16,0x51,0xC6,0x06,0x24,0x7A,0x01,0xC6,0x06,0x25,0x7A,0x01,0xC6,0x06,
+0x26,0x7A,0x03,0xC3,0xC7,0x06,0x0C,0x7A,0x1A,0x51,0xC7,0x06,0x0E,0x7A,0x4D,0x51,
+0xC7,0x06,0x10,0x7A,0x47,0x51,0xC7,0x06,0x12,0x7A,0x4A,0x51,0xC7,0x06,0x14,0x7A,
+0x4F,0x51,0xC7,0x06,0x16,0x7A,0x51,0x51,0xC7,0x06,0x18,0x7A,0x55,0x51,0xC7,0x06,
+0x1A,0x7A,0x56,0x51,0xC7,0x06,0x1C,0x7A,0x59,0x51,0xC7,0x06,0x1E,0x7A,0x5A,0x51,
+0xC7,0x06,0x20,0x7A,0x5B,0x51,0xC7,0x06,0x22,0x7A,0x5E,0x51,0xC6,0x06,0x24,0x7A,
+0x20,0xC6,0x06,0x25,0x7A,0x20,0xC6,0x06,0x26,0x7A,0x02,0xC3,0xA1,0xF8,0x79,0x48,
+0x74,0x14,0xBE,0xD7,0x79,0xE8,0x3C,0x00,0x8B,0xF8,0xAC,0x3C,0x3A,0x75,0x07,0x8E,
+0xC7,0xE8,0x30,0x00,0x8B,0xF8,0xC3,0x90,0x8B,0xC7,0x2B,0x06,0xFE,0x79,0x8A,0xF0,
+0x24,0x0F,0x8A,0xD0,0x02,0xD0,0x02,0xD0,0x80,0xC2,0x0B,0xC0,0xEE,0x04,0x80,0xC6,
+0x03,0x04,0x3D,0xC3,0x8C,0xC0,0xE8,0x93,0x00,0xB0,0x3A,0xE8,0xE4,0x00,0x8B,0xC7,
+0xE8,0x89,0x00,0xC3,0x51,0x33,0xC9,0x90,0xAC,0x3C,0x20,0x74,0xFB,0x90,0x0A,0xC0,
+0x74,0x26,0x2C,0x30,0x72,0x22,0x3C,0x09,0x76,0x14,0x3C,0x11,0x72,0x1A,0x2C,0x07,
+0x3C,0x0F,0x76,0x0A,0x3C,0x2A,0x72,0x10,0x2C,0x20,0x3C,0x0F,0x77,0x0A,0x98,0xC1,
+0xE1,0x04,0x03,0xC8,0xAC,0xEB,0xD7,0x90,0x4E,0x8B,0xC1,0x59,0xC3,0x90,0x06,0x8C,
+0xC8,0x8E,0xC0,0xE8,0x02,0x00,0x07,0xC3,0x26,0x8A,0x04,0x46,0x0A,0xC0,0x74,0x06,
+0xE8,0x8F,0x00,0xEB,0xF3,0x90,0xC3,0x90,0x0B,0xC0,0x74,0x7A,0x51,0x33,0xD2,0xB9,
+0xE8,0x03,0xF7,0xF1,0x8B,0xCA,0xE8,0x03,0x00,0x8B,0xC1,0x59,0xBA,0x64,0x00,0xF6,
+0xF2,0xE8,0x0C,0x00,0x8A,0xC4,0x98,0xB2,0x0A,0xF6,0xF2,0xE8,0x02,0x00,0x8A,0xC4,
+0x50,0x0A,0xF0,0x74,0x05,0x04,0x30,0xE8,0x58,0x00,0x58,0xC3,0x86,0xC4,0xE8,0x07,
+0x00,0x86,0xC4,0xE8,0x02,0x00,0xC3,0x90,0xC1,0xC8,0x04,0xE8,0x08,0x00,0xC1,0xC0,
+0x04,0xE8,0x02,0x00,0xC3,0x90,0x53,0x50,0x24,0x0F,0xBB,0xCA,0x62,0x2E,0xD7,0xE8,
+0x30,0x00,0x58,0x5B,0xC3,0x90,0x86,0xC4,0xE8,0x07,0x00,0x86,0xC4,0xE8,0x02,0x00,
+0xC3,0x90,0x50,0xB9,0x08,0x00,0x8A,0xE0,0x32,0xC0,0xD1,0xC0,0x04,0x30,0xE8,0x11,
+0x00,0xE2,0xF5,0x58,0xC3,0x90,0xB0,0x30,0xE8,0x07,0x00,0xC3,0xB0,0x20,0xE8,0x01,
+0x00,0xC3,0x56,0x8B,0x36,0xD0,0x79,0x88,0x84,0xD0,0x77,0x46,0x81,0xE6,0xFF,0x01,
+0xFF,0x06,0xD4,0x79,0x89,0x36,0xD0,0x79,0x81,0x3E,0xD4,0x79,0xFE,0x01,0x75,0x08,
+0x56,0xE8,0x14,0x00,0x5E,0xEB,0xF1,0x90,0x5E,0xC3,0xBA,0x02,0x02,0xEC,0x24,0x01,
+0x74,0x04,0xBA,0x06,0x02,0xEC,0xC3,0x90,0x80,0x3E,0xF6,0x79,0x00,0x74,0x09,0x60,
+0xB8,0x01,0x00,0xE8,0x2C,0xEA,0x61,0x90,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x28,
+0x8B,0x36,0xD2,0x79,0x83,0x3E,0xD4,0x79,0x00,0x74,0x1D,0x8A,0x84,0xD0,0x77,0x46,
+0x81,0xE6,0xFF,0x01,0x89,0x36,0xD2,0x79,0xFF,0x0E,0xD4,0x79,0xBA,0x06,0x02,0xEE,
+0xBA,0x02,0x02,0xEC,0xA8,0x04,0x75,0xDC,0xA1,0xD4,0x79,0xC3,0x52,0xBA,0x06,0x02,
+0xEE,0x5A,0xC3,0x90,0x52,0x50,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x08,0x58,0x5A,
+0xE8,0xE9,0xFF,0xF9,0xC3,0x90,0x58,0x5A,0xF8,0xC3,0x52,0x50,0xBA,0x02,0x02,0xEC,
+0xA8,0x04,0x74,0xFB,0x58,0x5A,0xE8,0xD3,0xFF,0xC3,0x30,0x31,0x32,0x33,0x34,0x35,
+0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x53,0x50,0x8A,0xE0,0x80,0xE4,
+0x0F,0xBB,0xCA,0x62,0xC0,0xE8,0x04,0x2E,0xD7,0xE8,0xCE,0xFF,0x8A,0xC4,0x2E,0xD7,
+0xE8,0xC7,0xFF,0x58,0x5B,0xC3,0x86,0xE0,0xE8,0xDF,0xFF,0x86,0xE0,0xE8,0xDA,0xFF,
+0xC3,0x90,0xBE,0xB2,0x4D,0x50,0x2E,0xAC,0x3C,0x00,0x74,0x05,0xE8,0xAB,0xFF,0xEB,
+0xF5,0x58,0xC3,0x90,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0xBF,0x04,0x00,
+0xC7,0x46,0xFC,0x00,0x00,0xC7,0x46,0xFA,0x00,0x00,0xC7,0x46,0xF8,0x00,0x00,0x83,
+0x7E,0x06,0x00,0x75,0x0E,0x56,0xE8,0xB6,0x0E,0x59,0x0B,0xC0,0x75,0x05,0x8B,0xC7,
+0xE9,0x5B,0x01,0x8B,0x46,0xFC,0x89,0x46,0xFE,0x0B,0xFF,0x75,0x05,0xB8,0x01,0x00,
+0xEB,0x02,0x33,0xC0,0x50,0x56,0xE8,0xA4,0x0D,0x59,0x59,0xB4,0x00,0x89,0x46,0xFC,
+0x8B,0x5E,0xFC,0x83,0xFB,0x08,0x76,0x03,0xE9,0x2B,0x01,0xD1,0xE3,0x2E,0xFF,0xA7,
+0xB2,0x64,0xB8,0x03,0x00,0xE9,0x26,0x01,0x83,0x7E,0xFA,0x00,0x74,0x14,0xC7,0x46,
+0xFA,0x00,0x00,0x8A,0x44,0x58,0x98,0x50,0x8A,0x44,0x59,0x98,0x50,0xE8,0xC2,0x0F,
+0x59,0x59,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8,0x9B,
+0x08,0x59,0x83,0x7E,0x06,0x00,0x75,0x05,0x8B,0xC7,0xE9,0xF1,0x00,0x83,0xFF,0x04,
+0x75,0x03,0xE9,0xE6,0x00,0x8B,0xC7,0xE9,0xE4,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03,
+0xBF,0x02,0x00,0xE9,0xD5,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03,0xBF,0x01,0x00,0xE9,
+0xC9,0x00,0x8B,0x5E,0xFE,0x83,0xFB,0x07,0x76,0x03,0xE9,0x86,0x00,0xD1,0xE3,0x2E,
+0xFF,0xA7,0xA2,0x64,0x33,0xFF,0xE9,0x7F,0x00,0xBF,0x04,0x00,0x80,0x7C,0x58,0x0F,
+0x74,0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x44,0x58,0x6A,0x08,0x56,0xE8,0x7E,
+0x0C,0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x72,0x0C,0x59,0x59,0xC7,
+0x46,0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,
+0xE8,0x19,0x08,0x59,0xEB,0x42,0xBF,0x04,0x00,0x80,0x7C,0x58,0x00,0x74,0x22,0x83,
+0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x4C,0x58,0x6A,0x08,0x56,0xE8,0x41,0x0C,0x59,0x59,
+0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x35,0x0C,0x59,0x59,0xC7,0x46,0xFA,0x01,
+0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8,0xDC,0x07,
+0x59,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xEB,0x31,0xBF,0x04,0x00,0xEB,0x2C,0xC7,
+0x46,0xF8,0x01,0x00,0x6A,0x08,0x56,0xE8,0x05,0x0C,0x59,0x59,0x80,0x7C,0x58,0x09,
+0x7D,0x04,0xB0,0x0F,0xEB,0x02,0xB0,0x00,0x04,0x80,0x50,0x56,0xE8,0xF0,0x0B,0x59,
+0x59,0xBF,0x04,0x00,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xE9,0xA5,0xFE,0x5F,0x5E,
+0xC9,0xC3,0xE4,0x63,0x63,0x64,0x63,0x64,0x63,0x64,0x63,0x64,0xE9,0x63,0x26,0x64,
+0x51,0x64,0x78,0x63,0xBA,0x63,0xC6,0x63,0x96,0x64,0xD2,0x63,0x6A,0x64,0x6A,0x64,
+0x6F,0x64,0x72,0x63,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8B,0x7E,0x08,
+0x6A,0x01,0x56,0xE8,0xA9,0x0B,0x59,0x59,0x8A,0x46,0x06,0xC0,0xE0,0x06,0x04,0x80,
+0x50,0x56,0xE8,0x9A,0x0B,0x59,0x59,0xC7,0x46,0xFE,0x00,0x00,0x89,0x7E,0xF8,0xEB,
+0x03,0xFF,0x46,0xFE,0x8B,0x5E,0xF8,0xFF,0x46,0xF8,0x80,0x3F,0x00,0x75,0xF2,0x83,
+0x7E,0xFE,0x10,0x7D,0x25,0xB8,0x10,0x00,0x2B,0x46,0xFE,0xD1,0xF8,0x89,0x46,0xFC,
+0xC7,0x46,0xFA,0x00,0x00,0xEB,0x0B,0x6A,0x20,0x56,0xE8,0x62,0x0B,0x59,0x59,0xFF,
+0x46,0xFA,0x8B,0x46,0xFA,0x3B,0x46,0xFC,0x7C,0xED,0xEB,0x0C,0x8B,0xDF,0x47,0x8A,
+0x07,0x50,0x56,0xE8,0x49,0x0B,0x59,0x59,0x80,0x3D,0x00,0x75,0xEF,0x6A,0x02,0x56,
+0xE8,0x3C,0x0B,0x59,0x59,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56,
+0x57,0x8B,0x7E,0x04,0xC7,0x46,0xFE,0x00,0x00,0xBE,0x14,0x00,0xE9,0x09,0x01,0x8B,
+0x5E,0xFE,0x83,0xC3,0x04,0x2B,0xDF,0x8A,0x87,0xAC,0x0B,0x88,0x44,0x5A,0xC6,0x44,
+0x58,0x08,0x8A,0x46,0xFE,0x88,0x44,0x59,0xC7,0x44,0x06,0x00,0x00,0xC6,0x44,0x19,
+0x00,0xC6,0x44,0x1A,0x00,0xC6,0x44,0x1B,0x00,0xC6,0x44,0x1D,0x0D,0xC6,0x44,0x1E,
+0x03,0xC6,0x44,0x1F,0x00,0xC6,0x44,0x20,0x00,0xC6,0x44,0x21,0x00,0xC6,0x44,0x5B,
+0x00,0xC6,0x44,0x5D,0x00,0xC6,0x44,0x5E,0x00,0xC6,0x44,0x5F,0x00,0xC6,0x44,0x60,
+0x00,0xC7,0x46,0xFC,0x00,0x00,0xEB,0x0D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x40,0x30,
+0x00,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x10,0x7C,0xED,0xC7,0x46,0xFC,0x00,0x00,
+0xEB,0x0A,0x8B,0x5E,0xFC,0xC6,0x40,0x50,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x04,
+0x7C,0xF0,0xC7,0x44,0x54,0x00,0x00,0xC7,0x44,0x56,0x00,0x00,0x8A,0x44,0x5A,0x98,
+0xBA,0xF8,0x00,0x23,0xD0,0xB8,0x05,0x00,0x0B,0xC2,0x89,0x46,0xFC,0x9C,0xFA,0x8A,
+0x46,0xFC,0xBA,0xFE,0x00,0xEE,0xBA,0x00,0x00,0xEC,0x9D,0x24,0x08,0x88,0x46,0xFC,
+0x83,0x7E,0xFC,0x00,0x75,0x02,0xEB,0x4A,0xFF,0x76,0xFE,0xE8,0x7A,0x0C,0x59,0x68,
+0x35,0x02,0x56,0xE8,0x32,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x34,0x68,0x38,0x02,0x56,
+0xE8,0x25,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x27,0x68,0x42,0x02,0x56,0xE8,0x18,0x0A,
+0x59,0x59,0x0B,0xC0,0x75,0x1A,0x68,0x4C,0x02,0x56,0xE8,0x0B,0x0A,0x59,0x59,0x0B,
+0xC0,0x75,0x0D,0x68,0x56,0x02,0x56,0xE8,0xFE,0x09,0x59,0x59,0x0B,0xC0,0x74,0x02,
+0xEB,0x00,0xFF,0x46,0xFE,0x83,0xC6,0x62,0x39,0x7E,0xFE,0x7D,0x03,0xE9,0xEF,0xFE,
+0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x46,0x04,0xBA,
+0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x8B,0xF0,0x83,0x7E,0x06,0x00,0x74,0x05,0xB8,
+0x10,0x00,0xEB,0x03,0xB8,0x08,0x00,0x89,0x44,0x04,0x8A,0x46,0x08,0x88,0x44,0x5C,
+0x56,0xE8,0x59,0x04,0x59,0x8B,0xF8,0x8B,0xC7,0x89,0x44,0x56,0x89,0x44,0x54,0x8A,
+0x44,0x5D,0x88,0x44,0x2F,0x0B,0xFF,0x75,0x1D,0x68,0xC2,0x0F,0x6A,0x01,0x56,0xE8,
+0x02,0xFE,0x83,0xC4,0x06,0xEB,0x00,0x6A,0x01,0x56,0xE8,0x47,0xFC,0x59,0x59,0x0B,
+0xC0,0x75,0xF4,0xBF,0x01,0x00,0x89,0x7E,0xFA,0xB9,0x05,0x00,0xBB,0xE9,0x6A,0x2E,
+0x8B,0x07,0x3B,0x46,0xFA,0x74,0x07,0x43,0x43,0xE2,0xF4,0xE9,0xA4,0x03,0x2E,0xFF,
+0x67,0x0A,0xC7,0x44,0x06,0x02,0x00,0xC7,0x44,0x08,0xF4,0x08,0x8B,0x5E,0x04,0xD1,
+0xE3,0x8B,0x87,0xFC,0x08,0x89,0x44,0x0A,0x33,0xC0,0x8B,0xF8,0x89,0x44,0x54,0xE9,
+0x80,0x03,0x56,0xE8,0xBB,0x05,0x59,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x60,
+0xE9,0x6F,0x03,0x83,0x7C,0x04,0x08,0x75,0x30,0x80,0x7C,0x5C,0x01,0x75,0x15,0x8A,
+0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xE4,0x08,0x56,0xE8,0xF7,0x08,
+0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xC4,
+0x08,0x56,0xE8,0xE2,0x08,0x59,0x59,0xEB,0x2E,0x80,0x7C,0x5C,0x01,0x75,0x15,0x8A,
+0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xD4,0x08,0x56,0xE8,0xC7,0x08,
+0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xB4,
+0x08,0x56,0xE8,0xB2,0x08,0x59,0x59,0x6A,0x01,0x56,0xE8,0x87,0xFB,0x59,0x59,0x8B,
+0xD8,0x83,0xFB,0x03,0x77,0x2A,0xD1,0xE3,0x2E,0xFF,0xA7,0xE1,0x6A,0xBF,0x01,0x00,
+0x8A,0x44,0x5D,0x88,0x44,0x5E,0xEB,0x18,0x8A,0x44,0x5D,0x04,0xFF,0x24,0x07,0x88,
+0x44,0x5D,0xEB,0x0C,0x8A,0x44,0x5D,0xFE,0xC0,0x24,0x07,0x88,0x44,0x5D,0xEB,0x00,
+0xE9,0xCF,0x02,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xFD,0x02,
+0x56,0xE8,0x63,0x08,0x59,0x59,0x68,0x1D,0x03,0x56,0xE8,0x5A,0x08,0x59,0x59,0x6A,
+0x01,0x56,0xE8,0x2F,0xFB,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x36,0xD1,0xE3,
+0x2E,0xFF,0xA7,0xD9,0x6A,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5F,0xEB,0x24,
+0x8A,0x44,0x5D,0x04,0xFF,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88,0x44,0x5D,
+0xEB,0x12,0x8A,0x44,0x5D,0xFE,0xC0,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88,
+0x44,0x5D,0xEB,0x00,0xE9,0x6B,0x02,0x8B,0x5C,0x06,0x83,0xC3,0xFE,0xD1,0xE3,0x8B,
+0x40,0x08,0x89,0x04,0x8B,0x1C,0xFF,0x77,0x06,0x6A,0x00,0x56,0xE8,0x85,0xFC,0x83,
+0xC4,0x06,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x40,0x08,0x89,0x44,0x02,0x8B,0x5C,
+0x02,0xFF,0x77,0x06,0x6A,0x01,0x56,0xE8,0x6A,0xFC,0x83,0xC4,0x06,0x6A,0x01,0x56,
+0xE8,0xB1,0xFA,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x76,0x03,0xE9,0x1F,0x02,0xD1,
+0xE3,0x2E,0xFF,0xA7,0xD1,0x6A,0x8B,0x5C,0x02,0x8B,0x47,0x04,0x89,0x44,0x02,0x8B,
+0x5C,0x02,0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B,
+0x44,0x04,0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02,
+0x89,0x47,0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9,
+0xDE,0x01,0x8B,0x5C,0x02,0x8B,0x47,0x02,0x89,0x44,0x02,0x8B,0x5C,0x02,0x80,0x3F,
+0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B,0x44,0x04,0x7D,0xE2,
+0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02,0x89,0x47,0x08,0x8B,
+0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9,0xA2,0x01,0xBF,0x01,
+0x00,0xE9,0x9C,0x01,0x8B,0x5C,0x02,0x8A,0x07,0xB4,0x00,0x89,0x46,0xF8,0xB9,0x0C,
+0x00,0xBB,0xA1,0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xF8,0x74,0x07,0x43,0x43,0xE2,0xF4,
+0xE9,0x77,0x01,0x2E,0xFF,0x67,0x18,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x5C,0x02,0x03,
+0xD8,0x8B,0x47,0x08,0x8B,0x5C,0x06,0xFF,0x44,0x06,0xD1,0xE3,0x89,0x40,0x08,0x8B,
+0x1C,0x80,0x7F,0x01,0x00,0x74,0x12,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,
+0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x40,0x01,0xFF,0x4C,0x06,0xE9,
+0x3A,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,
+0xDA,0x88,0x40,0x18,0xE9,0x25,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,
+0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xFF,0x4C,0x06,0xE9,0x0D,0x01,0x8B,
+0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x30,0x40,
+0x18,0xE9,0xF8,0x00,0xB8,0xF0,0x10,0x8B,0xF8,0x89,0x44,0x54,0x8A,0x44,0x5F,0x88,
+0x44,0x5D,0xE9,0xE7,0x00,0x8A,0x44,0x1C,0x98,0x3D,0x02,0x00,0x74,0x07,0x3D,0x03,
+0x00,0x74,0x02,0xEB,0x07,0xC7,0x46,0xFE,0x00,0x00,0xEB,0x2B,0x8A,0x44,0x1C,0x98,
+0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x69,0x02,0x56,0xE8,0x6B,0x06,0x59,0x59,0x6A,0x01,
+0x56,0xE8,0x40,0xF9,0x59,0x59,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x00,0x74,0x06,0x83,
+0x7E,0xFE,0x03,0x75,0xE9,0xEB,0x00,0x83,0x7E,0xFE,0x03,0x74,0x62,0x8A,0x44,0x1C,
+0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x6D,0x02,0x56,0xE8,0x3A,0x06,0x59,0x59,0x56,
+0xE8,0x4D,0x97,0x59,0x89,0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xEB,0xFE,0x83,0xFB,0x03,
+0x77,0x33,0xD1,0xE3,0x2E,0xFF,0xA7,0x99,0x6A,0x68,0xAC,0x02,0x56,0xE8,0x17,0x06,
+0x59,0x59,0xEB,0x23,0x68,0x8F,0x02,0x56,0xE8,0x0C,0x06,0x59,0x59,0xEB,0x18,0x68,
+0x75,0x02,0x56,0xE8,0x01,0x06,0x59,0x59,0xEB,0x0D,0x68,0xC6,0x02,0x56,0xE8,0xF6,
+0x05,0x59,0x59,0xEB,0x02,0xEB,0x00,0x6A,0x01,0x56,0xE8,0xC7,0xF8,0x59,0x59,0xBF,
+0x01,0x00,0xEB,0x38,0x68,0xDD,0x02,0x56,0xE8,0xDC,0x05,0x59,0x59,0x6A,0x01,0x56,
+0xE8,0xB1,0xF8,0x59,0x59,0xBF,0x01,0x00,0xEB,0x22,0xB8,0xD0,0x30,0x8B,0xF8,0x89,
+0x44,0x54,0x8A,0x44,0x60,0x88,0x44,0x5D,0xEB,0x12,0xB8,0xE0,0x20,0x8B,0xF8,0x89,
+0x44,0x54,0x8A,0x44,0x5E,0x88,0x44,0x5D,0xEB,0x02,0xEB,0x00,0xEB,0x02,0xEB,0x00,
+0xEB,0x00,0xE9,0x41,0xFC,0x5F,0x5E,0xC9,0xC3,0x19,0x6A,0x24,0x6A,0x2F,0x6A,0x3A,
+0x6A,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44,
+0x00,0x80,0x00,0x81,0x00,0x82,0x00,0xFF,0x00,0x17,0x69,0x54,0x6A,0x7A,0x6A,0xA5,
+0x69,0x52,0x69,0x94,0x69,0x6A,0x6A,0x67,0x69,0x52,0x69,0x7F,0x69,0x67,0x69,0x4C,
+0x69,0xF4,0x68,0x76,0x68,0xB2,0x68,0xEE,0x68,0xF5,0x67,0x00,0x68,0x12,0x68,0xF5,
+0x67,0x9D,0x67,0xA8,0x67,0xB4,0x67,0x9D,0x67,0x00,0x00,0x01,0x00,0xF0,0x10,0xE0,
+0x20,0xD0,0x30,0x27,0x68,0xF2,0x66,0xC3,0x67,0x23,0x67,0x12,0x67,0xC8,0x04,0x00,
+0x00,0x56,0x57,0x8B,0x76,0x04,0x8A,0x44,0x59,0x98,0x89,0x46,0xFC,0x6A,0x09,0x8B,
+0x46,0xFC,0x05,0x84,0x01,0x50,0xE8,0x93,0x08,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0x25,
+0x00,0xF0,0x3D,0x00,0x10,0x75,0x55,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xF0,0x00,0x75,
+0x4B,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B,
+0x46,0xFE,0x7D,0x05,0x33,0xC0,0xE9,0xEF,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,
+0x00,0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xE9,0xDB,0x00,0xC7,0x44,0x02,
+0x04,0x09,0x8A,0x46,0xFE,0x88,0x44,0x5F,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,
+0xC7,0x87,0xFC,0x08,0x04,0x09,0xB8,0xF0,0x10,0xE9,0xBC,0x00,0x8B,0xC7,0x25,0x00,
+0xF0,0x3D,0x00,0x20,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xE0,0x00,0x75,0x48,
+0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x08,0x7E,
+0x05,0x33,0xC0,0xE9,0x92,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0,
+0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xEB,0x7F,0x90,0xC7,0x44,0x02,0x0C,0x09,0x8A,
+0x46,0xFE,0x88,0x44,0x5E,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC,
+0x08,0x0C,0x09,0xB8,0xE0,0x20,0xEB,0x60,0x8B,0xC7,0x25,0x00,0xF0,0x3D,0x00,0x30,
+0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xD0,0x00,0x75,0x48,0x8B,0xC7,0x25,0x00,
+0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B,0x46,0xFE,0x7D,0x04,0x33,
+0xC0,0xEB,0x35,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0,0x3B,0x56,0xFE,
+0x74,0x04,0x33,0xC0,0xEB,0x22,0xC7,0x44,0x02,0x14,0x09,0x8A,0x46,0xFE,0x88,0x44,
+0x60,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x14,0x09,0xB8,
+0xD0,0x30,0xEB,0x04,0x33,0xC0,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00,
+0x56,0x8B,0x76,0x04,0x6A,0x08,0x56,0xE8,0x35,0x04,0x59,0x59,0x8A,0x44,0x58,0x04,
+0x80,0x50,0x56,0xE8,0x29,0x04,0x59,0x59,0x8B,0x44,0x54,0x3B,0x44,0x56,0x75,0x0A,
+0x8A,0x44,0x5D,0x3A,0x44,0x2F,0x75,0x02,0xEB,0x64,0x8B,0x44,0x54,0x89,0x44,0x56,
+0x8B,0x5C,0x02,0x8A,0x47,0x01,0x88,0x44,0x2F,0x8A,0x44,0x5D,0xB4,0x00,0xC1,0xE0,
+0x08,0x8B,0x54,0x54,0x0B,0xD0,0x8A,0x44,0x5D,0xB4,0x00,0xBB,0x0F,0x00,0x2B,0xD8,
+0x0B,0xD3,0x89,0x56,0xFE,0x6A,0x10,0x8A,0x44,0x59,0x98,0x05,0x04,0x00,0x99,0x05,
+0x40,0x01,0x83,0xD2,0x00,0x52,0x50,0xE8,0x54,0x08,0x83,0xC4,0x06,0x89,0x56,0xFC,
+0x89,0x46,0xFA,0x8B,0x46,0xFE,0x09,0x46,0xFA,0x83,0x4E,0xFC,0x00,0x6A,0x19,0xFF,
+0x76,0xFC,0xFF,0x76,0xFA,0xE8,0x73,0x07,0x83,0xC4,0x06,0xE8,0xFE,0x07,0x5E,0xC9,
+0xC3,0xC8,0x1C,0x00,0x00,0x56,0x57,0x8B,0x5E,0x04,0x8A,0x47,0x59,0x98,0x8B,0xF0,
+0x8B,0x5E,0x04,0x8A,0x47,0x5D,0xB4,0x00,0x89,0x46,0xE6,0x83,0x7E,0xE6,0x00,0x7D,
+0x0A,0x8B,0x5E,0x04,0x8B,0x47,0x04,0x48,0x89,0x46,0xE6,0x8B,0x5E,0x04,0x8B,0x47,
+0x04,0x3B,0x46,0xE6,0x7F,0x05,0xC7,0x46,0xE6,0x00,0x00,0x8B,0x5E,0x04,0x8A,0x46,
+0xE6,0x88,0x47,0x5D,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x02,0x20,
+0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x03,0x30,0x8B,0xDE,0xD1,0xE3,
+0x8B,0x9F,0x61,0x02,0xC6,0x47,0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,
+0xC6,0x47,0x03,0x30,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,
+0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,
+0xE3,0x8B,0x9F,0x59,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33,0xD2,
+0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A,
+0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,
+0x88,0x57,0x02,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,
+0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,
+0x8B,0x9F,0x61,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33,0xD2,0xF7,
+0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,
+0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,
+0x57,0x02,0x8B,0x5E,0xE6,0xD1,0xE3,0xFF,0xB7,0x12,0x02,0x6A,0x00,0xFF,0x76,0x04,
+0xE8,0xD1,0xF6,0x83,0xC4,0x06,0x68,0xD3,0x0F,0x6A,0x01,0xFF,0x76,0x04,0xE8,0xC3,
+0xF6,0x83,0xC4,0x06,0xFF,0x76,0xE6,0x56,0xE8,0x01,0x93,0x59,0x59,0x89,0x56,0xF2,
+0x89,0x46,0xF0,0xFF,0x76,0xE6,0x56,0xE8,0x14,0x93,0x59,0x59,0x89,0x56,0xEE,0x89,
+0x46,0xEC,0x9C,0xFA,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89,0x46,0xEA,0xC4,0x5E,0xEC,
+0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D,0xC7,0x46,
+0xE4,0x01,0x00,0xE8,0xEE,0xA0,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC,
+0x2B,0x46,0xFE,0x3D,0xE8,0x03,0x73,0x03,0xE9,0x80,0x01,0x9C,0xFA,0xBA,0x50,0xFF,
+0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC,0x2B,0x46,0xFE,0x89,0x46,0xF8,0xC4,0x5E,0xF0,
+0x26,0x8B,0x07,0x2B,0x46,0xEA,0x89,0x46,0xF6,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89,
+0x46,0xEA,0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x2B,0x46,0xE8,0x89,0x46,0xF4,0xC4,0x5E,
+0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D,0x81,
+0x7E,0xF8,0xE8,0x03,0x76,0x1C,0xFF,0x76,0xF8,0xFF,0x76,0xF6,0xE8,0x76,0x01,0x59,
+0x59,0x89,0x46,0xF6,0xFF,0x76,0xF8,0xFF,0x76,0xF4,0xE8,0x68,0x01,0x59,0x59,0x89,
+0x46,0xF4,0xBF,0x0E,0x00,0xEB,0x17,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,
+0x01,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x01,0x20,0x47,0x83,0xFF,
+0x11,0x76,0xE4,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x0D,0x30,0x8B,
+0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x0D,0x30,0x83,0x7E,0xF6,0x09,0x77,
+0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF6,0x63,0x77,0x05,0xB8,0x0E,0x00,0xEB,
+0x1B,0x81,0x7E,0xF6,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,0x7E,0xF6,
+0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,0xEB,0x25,
+0x8B,0x46,0xF6,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,
+0xE3,0x8B,0x9F,0x59,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF6,0x33,0xD2,
+0xF7,0xF3,0x89,0x46,0xF6,0x83,0x7E,0xF6,0x00,0x75,0xD5,0x83,0x7E,0xF4,0x09,0x77,
+0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF4,0x63,0x77,0x05,0xB8,0x0E,0x00,0xEB,
+0x1B,0x81,0x7E,0xF4,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,0x7E,0xF4,
+0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,0xEB,0x25,
+0x8B,0x46,0xF4,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,
+0xE3,0x8B,0x9F,0x61,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF4,0x33,0xD2,
+0xF7,0xF3,0x89,0x46,0xF4,0x83,0x7E,0xF4,0x00,0x75,0xD5,0x8B,0xDE,0xD1,0xE3,0xFF,
+0xB7,0x59,0x02,0xFF,0x76,0x04,0xE8,0x6E,0x00,0x59,0x59,0x8B,0xDE,0xD1,0xE3,0xFF,
+0xB7,0x61,0x02,0xFF,0x76,0x04,0xE8,0x5E,0x00,0x59,0x59,0x6A,0x00,0xFF,0x76,0x04,
+0xE8,0x31,0xF3,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x1F,0xD1,0xE3,0x2E,0xFF,
+0xA7,0x1B,0x70,0xEB,0x22,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x4E,0xE6,0xEB,0x0C,0xC7,
+0x46,0xE4,0x00,0x00,0xFF,0x46,0xE6,0xEB,0x02,0xEB,0x00,0x83,0x7E,0xE4,0x00,0x74,
+0x03,0xE9,0x2A,0xFE,0xE9,0xD4,0xFC,0x5F,0x5E,0xC9,0xC3,0xF3,0x6F,0xF5,0x6F,0xFF,
+0x6F,0xF3,0x6F,0x09,0x70,0x55,0x8B,0xEC,0x8B,0x46,0x04,0xB9,0xE8,0x03,0xF7,0xE1,
+0x8B,0x4E,0x06,0xF7,0xF1,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06,0xEB,0x0E,
+0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x33,0x00,0x59,0x59,0x80,0x3C,
+0x00,0x75,0xED,0xEB,0x00,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06,0xEB,
+0x14,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x45,0x00,0x59,0x59,0x0B,
+0xC0,0x74,0x02,0xEB,0x07,0x80,0x3C,0x00,0x75,0xE7,0xEB,0x00,0x5E,0x5D,0xC3,0xC8,
+0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,
+0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D,
+0xE8,0x91,0x9E,0xEB,0xE9,0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0xEB,0x00,0x5E,
+0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,
+0xFE,0xE8,0xE6,0xA1,0x89,0x46,0xFC,0xE8,0xE0,0xA1,0x2B,0x46,0xFC,0x3D,0xB8,0x0B,
+0x76,0x05,0xB8,0x01,0x00,0xEB,0x23,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,
+0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D,0xE8,0x48,0x9E,0xEB,0xD9,0xBA,0x00,
+0x00,0x8A,0x46,0x06,0xEE,0x9D,0x33,0xC0,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x04,0x00,
+0x00,0x56,0x57,0x8B,0x76,0x04,0x83,0x7E,0x06,0x00,0x74,0x07,0x56,0xE8,0x03,0x01,
+0x59,0xEB,0x05,0x56,0xE8,0xA2,0x00,0x59,0x88,0x46,0xFF,0x80,0x7E,0xFF,0x08,0x77,
+0x06,0x8A,0x46,0xFF,0xE9,0x84,0x00,0x80,0x7E,0xFF,0x0F,0x76,0x03,0xEB,0x79,0x90,
+0x8A,0x46,0xFF,0xB4,0x00,0x2D,0x0A,0x00,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x67,0xD1,
+0xE3,0x2E,0xFF,0xA7,0xAF,0x71,0xB0,0x00,0xEB,0x61,0x56,0xE8,0x6B,0x00,0x59,0xB4,
+0x00,0x25,0x0F,0x00,0x89,0x46,0xFC,0x56,0xE8,0x5E,0x00,0x59,0xB4,0x00,0x8B,0xF8,
+0x56,0xE8,0x55,0x00,0x59,0xB4,0x00,0xC1,0xE0,0x08,0x8B,0xD7,0x03,0xD0,0x8B,0xFA,
+0x8B,0x5E,0xFC,0xD1,0xE3,0x89,0x78,0x30,0xEB,0x2E,0x56,0xE8,0x3B,0x00,0x59,0x88,
+0x44,0x5B,0xEB,0x24,0x56,0xE8,0x31,0x00,0x59,0x88,0x44,0x50,0x56,0xE8,0x29,0x00,
+0x59,0x88,0x44,0x51,0x56,0xE8,0x21,0x00,0x59,0x88,0x44,0x52,0x56,0xE8,0x19,0x00,
+0x59,0x88,0x44,0x53,0xEB,0x02,0xEB,0x00,0xE9,0x5B,0xFF,0x5F,0x5E,0xC9,0xC3,0x46,
+0x71,0xA6,0x71,0x4A,0x71,0x7A,0x71,0x84,0x71,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76,
+0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,
+0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x57,0x9D,0xEB,0xE9,0xBA,
+0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,
+0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,
+0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0x32,0xE4,0x24,0x01,0x9D,
+0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,
+0x46,0xFE,0xE8,0x85,0xA0,0x89,0x46,0xFA,0xE8,0x7F,0xA0,0x2B,0x46,0xFA,0x3D,0xB8,
+0x0B,0x76,0x04,0xB0,0x08,0xEB,0x24,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,
+0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0xE8,0x9C,0xEB,0xDA,0xBA,0x00,
+0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B,
+0xEC,0x56,0x8B,0x56,0x04,0x8A,0x46,0x06,0xEE,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46,
+0x83,0xFE,0x14,0x7C,0xF8,0x5E,0x5D,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x56,0x04,
+0xEC,0x88,0x46,0xFF,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46,0x83,0xFE,0x14,0x7C,0xF8,
+0x8A,0x46,0xFF,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x57,0x8B,0x76,
+0x04,0x83,0x3E,0xB0,0x0B,0x00,0x75,0x1F,0xBA,0x88,0x01,0xB0,0x00,0xEE,0xBA,0x86,
+0x01,0xB0,0x00,0xEE,0x6A,0x09,0x6A,0x00,0x68,0x30,0x01,0xE8,0x7D,0x01,0x83,0xC4,
+0x06,0xC7,0x06,0xB0,0x0B,0x01,0x00,0x6A,0x09,0x8B,0xC6,0x05,0x80,0x01,0x50,0xE8,
+0xDA,0x00,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0xC1,0xE8,0x0C,0x25,0x0F,0x00,0x89,0x46,
+0xFE,0x8B,0xC7,0xC1,0xE8,0x08,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2,0x0C,0x3B,
+0xC2,0x75,0x21,0x8B,0xC7,0xC1,0xE8,0x04,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2,
+0x06,0x3B,0xC2,0x75,0x0F,0x8B,0xC7,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2,0x09,
+0x3B,0xC2,0x74,0x0D,0x6A,0x07,0x56,0xE8,0x38,0x00,0x59,0x59,0xC7,0x46,0xFE,0x07,
+0x00,0x8A,0x46,0xFE,0x04,0x80,0xA2,0x33,0x02,0x8B,0xC6,0xBA,0x62,0x00,0xF7,0xEA,
+0x8A,0x56,0xFE,0x8B,0xD8,0x88,0x97,0x6C,0x00,0x68,0x32,0x02,0x8B,0xC6,0xBA,0x62,
+0x00,0xF7,0xEA,0x05,0x14,0x00,0x50,0xE8,0x0E,0xFD,0x59,0x59,0xEB,0x00,0x5F,0x5E,
+0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x06,0x83,0xE6,0x0F,0x8B,0xC6,0xC1,
+0xE0,0x0C,0x8B,0xD6,0x83,0xF2,0x0C,0xC1,0xE2,0x08,0x0B,0xC2,0x8B,0xD6,0x83,0xF2,
+0x06,0xC1,0xE2,0x04,0x0B,0xC2,0x8B,0xD6,0x83,0xF2,0x09,0x0B,0xC2,0x89,0x46,0xFE,
+0x6A,0x19,0x6A,0x10,0x8B,0x46,0x04,0x99,0x05,0x40,0x01,0x83,0xD2,0x00,0x52,0x50,
+0xE8,0x6B,0x01,0x83,0xC4,0x06,0x0B,0x46,0xFE,0x83,0xCA,0x00,0x52,0x50,0xE8,0x9A,
+0x00,0x83,0xC4,0x06,0xE8,0x25,0x01,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B,0xEC,0x56,
+0x57,0x33,0xFF,0x6A,0x01,0x68,0x86,0x01,0xE8,0xA3,0xFE,0x59,0x59,0xB1,0x10,0x2A,
+0x4E,0x06,0xD3,0x66,0x04,0x33,0xF6,0xEB,0x2E,0x81,0x7E,0x04,0x00,0x80,0x72,0x04,
+0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68,0x88,0x01,0xE8,0x81,0xFE,0x59,0x59,0x6A,
+0x03,0x68,0x86,0x01,0xE8,0x77,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0x6D,
+0xFE,0x59,0x59,0xD1,0x66,0x04,0x46,0x3B,0x76,0x06,0x7C,0xCD,0x33,0xF6,0xEB,0x24,
+0xD1,0xE7,0x6A,0x03,0x68,0x86,0x01,0xE8,0x54,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86,
+0x01,0xE8,0x4A,0xFE,0x59,0x59,0x68,0x88,0x01,0xE8,0x5C,0xFE,0x59,0x98,0x25,0x01,
+0x00,0x0B,0xF8,0x46,0x83,0xFE,0x10,0x7C,0xD7,0x6A,0x00,0x68,0x86,0x01,0xE8,0x2D,
+0xFE,0x59,0x59,0x8B,0xC7,0xEB,0x00,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x57,
+0x8B,0x7E,0x08,0x6A,0x01,0x68,0x86,0x01,0xE8,0x13,0xFE,0x59,0x59,0xB8,0x20,0x00,
+0x2B,0xC7,0x50,0xFF,0x76,0x06,0xFF,0x76,0x04,0xE8,0xA2,0x00,0x83,0xC4,0x06,0x89,
+0x56,0x06,0x89,0x46,0x04,0x33,0xF6,0xEB,0x47,0x81,0x7E,0x06,0x00,0x80,0x72,0x0C,
+0x75,0x06,0x83,0x7E,0x04,0x00,0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68,
+0x88,0x01,0xE8,0xD9,0xFD,0x59,0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0xCF,0xFD,0x59,
+0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0xC5,0xFD,0x59,0x59,0x6A,0x01,0xFF,0x76,0x06,
+0xFF,0x76,0x04,0xE8,0x58,0x00,0x83,0xC4,0x06,0x89,0x56,0x06,0x89,0x46,0x04,0x46,
+0x3B,0xF7,0x7C,0xB5,0x6A,0x00,0x68,0x86,0x01,0xE8,0xA2,0xFD,0x59,0x59,0x6A,0x00,
+0x68,0x86,0x01,0xE8,0x98,0xFD,0x59,0x59,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,
+0x6A,0x01,0x68,0x86,0x01,0xE8,0x86,0xFD,0x59,0x59,0x33,0xF6,0xEB,0x00,0x68,0x88,
+0x01,0xE8,0x94,0xFD,0x59,0xA8,0x01,0x75,0x08,0x8B,0xC6,0x46,0x3D,0x64,0x00,0x7C,
+0xED,0x6A,0x00,0x68,0x86,0x01,0xE8,0x65,0xFD,0x59,0x59,0x5E,0x5D,0xC3,0xC8,0x04,
+0x00,0x00,0x8B,0x46,0x04,0x8B,0x56,0x06,0x8B,0x4E,0x08,0xE3,0x06,0xD1,0xE0,0xD1,
+0xD2,0xE2,0xFA,0x89,0x46,0xFC,0x89,0x56,0xFE,0x8B,0x56,0xFE,0x8B,0x46,0xFC,0xEB,
+0x00,0xC9,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x50,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x4D,0x65,0x6E,0x75,0x00,0x42,0x65,
 0x67,0x69,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
@@ -2130,8 +2132,6 @@
 0x53,0x00,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x20,0x66,0x6F,0x72,0x20,0x6D,0x65,
 0x6E,0x75,0x00,0x28,0x63,0x6F,0x75,0x6E,0x74,0x69,0x6E,0x67,0x2E,0x2E,0x2E,0x29,
 0x00,0x00,0x65,0x4E,0x64,0x20,0x4F,0x66,0x20,0x43,0x6F,0x44,0x65,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2cmd.c linux/drivers/char/ip2/i2cmd.c
--- v2.3.99-pre5/linux/drivers/char/ip2/i2cmd.c	Thu Aug 26 13:05:35 1999
+++ linux/drivers/char/ip2/i2cmd.c	Mon Apr 24 13:39:35 2000
@@ -139,7 +139,7 @@
 //static UCHAR ct86[]={ 2, BTH,     0x56,0                   }; // RCV_ENABLE
 static UCHAR ct87[] = { 1, BYP,     0x57                     }; // HW_TEST
 //static UCHAR ct88[]={ 3, BTH,     0x58,0,0                 }; // RCV_THRESHOLD
-//static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
+static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
 //static UCHAR ct90[]={ 3, BYP,     0x5A,0,0                 }; // Set SILO
 //static UCHAR ct91[]={ 2, BYP,     0x5B,0                   }; // timed break
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2ellis.h linux/drivers/char/ip2/i2ellis.h
--- v2.3.99-pre5/linux/drivers/char/ip2/i2ellis.h	Thu Aug 26 13:05:35 1999
+++ linux/drivers/char/ip2/i2ellis.h	Tue Apr 25 17:52:01 2000
@@ -47,6 +47,7 @@
 //----------------------
 // Mandatory Includes:
 //----------------------
+#include <linux/config.h>
 #include "ip2types.h"
 #include "i2hw.h"       // The hardware definitions
 
@@ -399,6 +400,11 @@
 	spinlock_t	read_fifo_spinlock;
 	spinlock_t	write_fifo_spinlock;
 
+#ifdef	CONFIG_DEVFS_FS
+	/* Device handles into devfs */
+	devfs_handle_t	devfs_ipl_handle;
+	devfs_handle_t	devfs_stat_handle;
+#endif
 } i2eBordStr, *i2eBordStrPtr;
 
 //-------------------------------------------------------------------
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2lib.c linux/drivers/char/ip2/i2lib.c
--- v2.3.99-pre5/linux/drivers/char/ip2/i2lib.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/ip2/i2lib.c	Mon Apr 24 13:39:35 2000
@@ -1086,7 +1086,7 @@
 
 			// Move the data
 			if ( user ) {
-				rc=copy_from_user((char*)(DATA_OF(pInsert)), pSource,
+				COPY_FROM_USER(rc, (char*)(DATA_OF(pInsert)), pSource,
 						amountToMove );
 			} else {
 				memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );
@@ -1516,8 +1516,8 @@
 				return;     /* Bail out ASAP */
 			}
 			// Channel is illegally big ?
-			if (channel >= pB->i2eChannelCnt ||
-				(pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) == NULL)
+			if ((channel >= pB->i2eChannelCnt) ||
+				(NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])))
 			{
 				iiReadBuf(pB, junkBuffer, count);
 				WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
@@ -1541,7 +1541,8 @@
 
 			// Normal data! We crudely assume there is room for the data in our
 			// buffer because the board wouldn't have exceeded his credit limit.
-			WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);// We have 2 locks now
+			WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);
+													// We have 2 locks now
 			stuffIndex = pCh->Ibuf_stuff;
 			amountToRead = IBUF_SIZE - stuffIndex;
 			if (amountToRead > count)
@@ -1552,6 +1553,7 @@
 			// one.
 
 			iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead);
+			pCh->icount.rx += amountToRead;
 
 			// Update the stuffIndex by the amount of data moved. Note we could
 			// never ask for more data than would just fit. However, we might
@@ -1576,6 +1578,7 @@
 			if (count > amountToRead) {
 				amountToRead = count - amountToRead;
 				iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead);
+				pCh->icount.rx += amountToRead;
 				stuffIndex += amountToRead;
 			}
 
@@ -1632,7 +1635,7 @@
 						if ( !(pCh->dataSetIn & I2_CTS) )
 						{
 							pCh->dataSetIn |= I2_DCTS;
-							++pCh->icount.cts;
+							pCh->icount.cts++;
 							dss_change = 1;
 						}
 						pCh->dataSetIn |= I2_CTS;
@@ -1642,7 +1645,7 @@
 						if ( pCh->dataSetIn & I2_CTS )
 						{
 							pCh->dataSetIn |= I2_DCTS;
-							++pCh->icount.cts;
+							pCh->icount.cts++;
 							dss_change = 1;
 						}
 						pCh->dataSetIn &= ~I2_CTS;
@@ -1658,7 +1661,7 @@
 							ip2trace (CHANN, ITRC_MODEM, 2, 0 );
 #endif
 							pCh->dataSetIn |= I2_DDCD;
-							++pCh->icount.dcd;
+							pCh->icount.dcd++;
 							dss_change = 1;
 						}
 						pCh->dataSetIn |= I2_DCD;
@@ -1677,7 +1680,7 @@
 							ip2trace (channel, ITRC_MODEM, 5, 0 );
 #endif
 							pCh->dataSetIn |= I2_DDCD;
-							++pCh->icount.dcd;
+							pCh->icount.dcd++;
 							dss_change = 1;
 						}
 						pCh->dataSetIn &= ~I2_DCD;
@@ -1690,7 +1693,7 @@
 						if ( !(pCh->dataSetIn & I2_DSR) )
 						{
 							pCh->dataSetIn |= I2_DDSR;
-							++pCh->icount.dsr;
+							pCh->icount.dsr++;
 							dss_change = 1;
 						}
 						pCh->dataSetIn |= I2_DSR;
@@ -1700,7 +1703,7 @@
 						if ( pCh->dataSetIn & I2_DSR )
 						{
 							pCh->dataSetIn |= I2_DDSR;
-							++pCh->icount.dsr;
+							pCh->icount.dsr++;
 							dss_change = 1;
 						}
 						pCh->dataSetIn &= ~I2_DSR;
@@ -1710,23 +1713,26 @@
 						if ( !(pCh->dataSetIn & I2_RI) )
 						{
 							pCh->dataSetIn |= I2_DRI;
-							++pCh->icount.rng;
+							pCh->icount.rng++;
 							dss_change = 1;
 						}
 						pCh->dataSetIn |= I2_RI ;
 						break;
 
 					case STAT_RI_DN:
-						if ( pCh->dataSetIn & I2_RI )
-						{
-							pCh->dataSetIn |= I2_DRI;
-							dss_change = 1;
-						}
+						// to be compat with serial.c
+						//if ( pCh->dataSetIn & I2_RI )
+						//{
+						//	pCh->dataSetIn |= I2_DRI;
+						//	pCh->icount.rng++; 
+						//	dss_change = 1;
+						//}
 						pCh->dataSetIn &= ~I2_RI ;
 						break;
 
 					case STAT_BRK_DET:
 						pCh->dataSetIn |= I2_BRK;
+						pCh->icount.brk++;
 						dss_change = 1;
 						break;
 
@@ -1791,9 +1797,6 @@
 					case STAT_BOXIDS:
 						pB->channelBtypes = *((bidStatPtr)pc);
 						pc += sizeof(bidStat);
-//printk("boxids: %x %x %x %x\n",
-//	pB->channelBtypes.bid_value[0],pB->channelBtypes.bid_value[1],
-//	pB->channelBtypes.bid_value[2],pB->channelBtypes.bid_value[3]);
 						set_baud_params(pB);
 						break;
 
@@ -1810,18 +1813,26 @@
 						switch (uc & STAT_MOD_ERROR)
 						{
 						case STAT_ERROR:
-							if (uc & STAT_E_PARITY) 
+							if (uc & STAT_E_PARITY) {
 								pCh->dataSetIn |= I2_PAR;
-							if (uc & STAT_E_FRAMING) 
+								pCh->icount.parity++;
+							}
+							if (uc & STAT_E_FRAMING){
 								pCh->dataSetIn |= I2_FRA;
-							if (uc & STAT_E_OVERRUN) 
+								pCh->icount.frame++;
+							}
+							if (uc & STAT_E_OVERRUN){
 								pCh->dataSetIn |= I2_OVR;
+								pCh->icount.overrun++;
+							}
 							break;
 
 						case STAT_MODEM:
+							// the answer to DSS_NOW request (not change)
 							pCh->dataSetIn = (pCh->dataSetIn
 								& ~(I2_RI | I2_CTS | I2_DCD | I2_DSR) )
 								| xlatDss[uc & 0xf];
+							wake_up_interruptible ( &pCh->dss_now_wait );
 						default:
 							break;
 						}
@@ -1846,16 +1857,6 @@
 						pc += 4;    /* Skip the data */
 						break;
 
-					case STAT_CTS_UP:
-					case STAT_CTS_DN:
-					case STAT_DCD_UP:
-					case STAT_DCD_DN:
-					case STAT_DSR_UP:
-					case STAT_DSR_DN:
-					case STAT_RI_UP:
-					case STAT_RI_DN:
-					case STAT_BRK_DET:
-					case STAT_BMARK:
 					default:
 						break;
 					}
@@ -2102,6 +2103,7 @@
 #endif /* DEBUG_FIFO */
 			pB->debugInlineCount++;
 
+			pCh->icount.tx += flowsize;
 			// Update current credits
 			pCh->outfl.room -= flowsize;
 			pCh->outfl.asof += flowsize;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2lib.h linux/drivers/char/ip2/i2lib.h
--- v2.3.99-pre5/linux/drivers/char/ip2/i2lib.h	Thu Aug 26 13:05:35 1999
+++ linux/drivers/char/ip2/i2lib.h	Mon Apr 24 13:39:35 2000
@@ -67,8 +67,8 @@
 //
 #define MAX_CBUF_BLOCK  6	// Maximum total length of a bypass command block
 
-#define IBUF_SIZE       500	// character capacity of input buffer per channel
-#define OBUF_SIZE       2048// character capacity of output buffer per channel
+#define IBUF_SIZE       512	// character capacity of input buffer per channel
+#define OBUF_SIZE       1024// character capacity of output buffer per channel
 #define CBUF_SIZE       10	// character capacity of output bypass buffer
 
 typedef struct _i2ChanStr
@@ -97,6 +97,7 @@
 	PWAITQ   open_wait;     // Pointer for OS sleep function.
 	PWAITQ   close_wait;    // Pointer for OS sleep function.
 	PWAITQ   delta_msr_wait;// Pointer for OS sleep function.
+	PWAITQ   dss_now_wait;	// Pointer for OS sleep function.
 
 	struct timer_list  BookmarkTimer;   // Used by i2DrainOutput
 	wait_queue_head_t pBookmarkWait;   // Used by i2DrainOutput
@@ -215,7 +216,6 @@
 
 	void (*trace)(unsigned short,unsigned char,unsigned char,unsigned long,...);
 
-#ifdef __KERNEL__
 	/*
 	 * Kernel counters for the 4 input interrupts 
 	 */
@@ -227,7 +227,6 @@
 	struct tq_struct	tqueue_input;
 	struct tq_struct	tqueue_status;
 	struct tq_struct	tqueue_hangup;
-#endif 
 
 	spinlock_t Ibuf_spinlock;
 	spinlock_t Obuf_spinlock;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2mkdev.c linux/drivers/char/ip2/ip2mkdev.c
--- v2.3.99-pre5/linux/drivers/char/ip2/ip2mkdev.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ip2/ip2mkdev.c	Mon Apr 24 13:39:35 2000
@@ -0,0 +1,123 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <linux/major.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "ip2.h"
+#include "i2ellis.h"
+
+char nm[256];
+i2eBordStr Board[2];
+
+static void ex_details(i2eBordStrPtr);
+
+int main (int argc, char *argv[])
+{
+	int board, box, port;
+	int fd;
+	int dev;
+	i2eBordStrPtr pB  = Board;
+
+	// Remove all IP2 devices
+
+	for ( board = 0; board < 4; ++board )
+	{
+		sprintf ( nm, "/dev/ip2ipl%d", board );
+		unlink ( nm );
+		sprintf ( nm, "/dev/ip2stat%d", board );
+		unlink ( nm );
+	}
+
+	for ( port = 0; port < 256; ++port  )
+	{
+		sprintf ( nm, "/dev/ttyF%d", port );
+		unlink ( nm );
+		sprintf ( nm, "/dev/cuf%d", port );
+		unlink ( nm );
+	}
+
+	// Now create management devices, and use the status device to determine how
+	// port devices need to exist, and then create them.
+
+	for ( board = 0; board < 4; ++board )
+	{
+		printf("Board %d: ", board );
+
+		sprintf ( nm, "/dev/ip2ipl%d", board );
+		mknod ( nm, S_IFCHR|0666, (IP2_IPL_MAJOR << 8) | board * 4 );
+		sprintf ( nm, "/dev/ip2stat%d", board );
+		mknod ( nm, S_IFCHR|0666, (IP2_IPL_MAJOR << 8) | board * 4 + 1 );
+
+		fd = open ( nm, O_RDONLY );
+		if ( !fd )
+		{
+			printf ( "Unable to open status device %s\n", nm );
+			exit ( 1 );
+		}
+		if ( ioctl ( fd,  65, Board ) < 0 )
+		{
+			printf ( "not present\n" );
+			close ( fd );
+			unlink ( nm );
+			sprintf ( nm, "/dev/ip2ipl%d", board );
+			unlink ( nm );
+		}
+		else
+		{
+			switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) 
+			{
+			case POR_ID_FIIEX: ex_details ( pB );       break;
+			case POR_ID_II_4:  printf ( "ISA-4" );      break;
+			case POR_ID_II_8:  printf ( "ISA-8 std" );  break;
+			case POR_ID_II_8R: printf ( "ISA-8 RJ11" ); break;
+		
+			default:
+				printf ( "Unknown board type, ID = %x", pB->i2ePom.e.porID );
+			}
+
+			for ( box = 0; box < ABS_MAX_BOXES; ++box )
+			{
+				for ( port = 0; port < ABS_BIGGEST_BOX; ++port )
+				{
+					if ( pB->i2eChannelMap[box] & ( 1 << port ) )
+					{
+						dev = port 
+							 + box * ABS_BIGGEST_BOX 
+							 + board * ABS_BIGGEST_BOX * ABS_MAX_BOXES;
+	
+						sprintf ( nm, "/dev/ttyF%d", dev );
+						mknod ( nm, S_IFCHR|0666, (IP2_TTY_MAJOR << 8) | dev );
+						sprintf ( nm, "/dev/cuf%d", dev );
+						mknod ( nm, S_IFCHR|0666, (IP2_CALLOUT_MAJOR << 8) | dev );
+
+						printf(".");
+					}
+				}
+			}
+			printf("\n");
+		}
+	}
+}
+
+static void ex_details ( i2eBordStrPtr pB )
+{
+	int            box;
+	int            i;
+	int            ports = 0;
+	int            boxes = 0;
+
+	for( box = 0; box < ABS_MAX_BOXES; ++box )
+	{
+		if( pB->i2eChannelMap[box] != 0 ) ++boxes;
+		for( i = 0; i < ABS_BIGGEST_BOX; ++i ) 
+		{
+			if( pB->i2eChannelMap[box] & 1<< i ) ++ports;
+		}
+	}
+
+	printf("EX bx=%d pt=%d %d bit", boxes, ports, pB->i2eDataWidth16 ? 16 : 8 );
+}
+
+
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2stat.c linux/drivers/char/ip2/ip2stat.c
--- v2.3.99-pre5/linux/drivers/char/ip2/ip2stat.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ip2/ip2stat.c	Mon Apr 24 13:39:35 2000
@@ -0,0 +1,115 @@
+/*******************************************************************************
+*
+*   (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+*   PACKAGE:     Linux tty Device Driver for IntelliPort family of multiport
+*                serial I/O controllers.
+*
+*   DESCRIPTION: Status display utility
+*
+*******************************************************************************/
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <linux/timer.h>
+#include <linux/termios.h>
+
+#include "i2ellis.h"
+#include "i2lib.h"
+
+i2eBordStr Board[2];
+i2ChanStr  Port[2];
+
+struct driver_stats
+{
+	ULONG ref_count;
+	ULONG irq_counter;
+	ULONG bh_counter;
+} Driver;
+
+char	devname[20];
+
+int main (int argc, char *argv[])
+{
+   int   fd;
+   int   dev, i;
+	i2eBordStrPtr pB  = Board;
+	i2ChanStrPtr  pCh = Port;
+
+	if ( argc != 2 ) 
+	{
+		printf ( "Usage: %s <port>\n", argv[0] );
+		exit(1);
+	}
+	i = sscanf ( argv[1], "/dev/ttyF%d", &dev );
+
+	if ( i != 1 ) exit(1);
+
+	//printf("%s: board %d, port %d\n", argv[1], dev / 64, dev % 64 );
+
+	sprintf ( devname, "/dev/ip2stat%d", dev / 64 );
+	if( 0 > ( fd = open ( devname, O_RDONLY ) ) ) {
+		// Conventional name failed - try devfs name
+		sprintf ( devname, "/dev/ip2/stat%d", dev / 64 );
+		if( 0 > ( fd = open ( devname, O_RDONLY ) ) ) {
+			// Where is our board???
+			printf( "Unable to open board %d to retrieve stats\n",
+				dev / 64 );
+			exit( 255 );
+		}
+	}
+
+	ioctl ( fd,  64, &Driver );
+	ioctl ( fd,  65, Board );
+	ioctl ( fd,  dev % 64, Port );
+
+	printf ( "Driver statistics:-\n" );
+	printf ( " Reference Count:  %d\n", Driver.ref_count );
+	printf ( " Interrupts to date:   %ld\n", Driver.irq_counter );
+	printf ( " Bottom half to date:  %ld\n", Driver.bh_counter );
+
+	printf ( "Board statistics(%d):-\n",dev/64 );
+	printf ( "FIFO: remains = %d%s\n", pB->i2eFifoRemains, 
+				pB->i2eWaitingForEmptyFifo ? ", busy" : "" );
+	printf ( "Mail: out mail = %02x\n", pB->i2eOutMailWaiting ); 
+	printf ( "  Input interrupts : %d\n", pB->i2eFifoInInts );
+	printf ( "  Output interrupts: %d\n", pB->i2eFifoOutInts );
+	printf ( "  Flow queued      : %ld\n", pB->debugFlowQueued );
+	printf ( "  Bypass queued    : %ld\n", pB->debugBypassQueued );
+	printf ( "  Inline queued    : %ld\n", pB->debugInlineQueued );
+	printf ( "  Data queued      : %ld\n", pB->debugDataQueued );
+	printf ( "  Flow packets     : %ld\n", pB->debugFlowCount );
+	printf ( "  Bypass packets   : %ld\n", pB->debugBypassCount );
+	printf ( "  Inline packets   : %ld\n", pB->debugInlineCount );
+	printf ( "  Mail status      : %x\n",  pB->i2eStatus );
+	printf ( "  Output mail      : %x\n",  pB->i2eOutMailWaiting );
+	printf ( "  Fatal flag       : %d\n",  pB->i2eFatal );
+
+	printf ( "Channel statistics(%s:%d):-\n",argv[1],dev%64 );
+	printf ( "ibuf: stuff = %d strip = %d\n", pCh->Ibuf_stuff, pCh->Ibuf_strip );
+	printf ( "obuf: stuff = %d strip = %d\n", pCh->Obuf_stuff, pCh->Obuf_strip );
+	printf ( "pbuf: stuff = %d\n", pCh->Pbuf_stuff );
+	printf ( "cbuf: stuff = %d strip = %d\n", pCh->Cbuf_stuff, pCh->Cbuf_strip );
+	printf ( "infl: count = %d room = %d\n", pCh->infl.asof, pCh->infl.room );
+	printf ( "outfl: count = %d room = %d\n", pCh->outfl.asof, pCh->outfl.room );
+	printf ( "throttled = %d ",pCh->throttled);
+	printf ( "bookmarks = %d ",pCh->bookMarks);
+	printf ( "flush_flags = %x\n",pCh->flush_flags);
+	printf ( "needs: ");
+	if (pCh->channelNeeds & NEED_FLOW)   printf("FLOW ");
+	if (pCh->channelNeeds & NEED_INLINE) printf("INLINE ");
+	if (pCh->channelNeeds & NEED_BYPASS) printf("BYPASS ");
+	if (pCh->channelNeeds & NEED_CREDIT) printf("CREDIT ");
+	printf ( "\n");
+	printf ( "dss: in = %x, out = %x\n",pCh->dataSetIn,pCh->dataSetOut);
+	
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.c linux/drivers/char/ip2/ip2trace.c
--- v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ip2/ip2trace.c	Mon Apr 24 13:39:35 2000
@@ -0,0 +1,279 @@
+/*******************************************************************************
+*
+*   (c) 1998 by Computone Corporation
+*
+********************************************************************************
+*
+*
+*   PACKAGE:     Linux tty Device Driver for IntelliPort family of multiport
+*                serial I/O controllers.
+*
+*   DESCRIPTION: Interpretive trace dump utility
+*
+*******************************************************************************/
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include "ip2trace.h"
+
+unsigned long namebuf[100];
+
+struct { 
+	int wrap,
+	size,
+	o_strip,
+	o_stuff,
+	strip,
+	stuff;
+	unsigned long buf[1000];
+} tbuf;
+
+struct sigaction act;
+
+typedef enum { kChar, kInt, kAddr, kHex } eFormat;
+
+int active = 1;
+void quit() { active = 0; }
+
+int main (int argc, char *argv[])
+{
+   int   fd = open ( "/dev/ip2trace", O_RDONLY );
+   int   cnt, i;
+	unsigned long ts, td;
+   struct timeval timeout;
+   union ip2breadcrumb bc;
+	eFormat fmt = kHex;
+
+   if ( fd < 0 )
+   {
+      printf ( "Can't open device /dev/ip2trace\n" );
+      exit ( 1 );
+   }
+
+   act.sa_handler = quit;
+   /*act.sa_mask = 0;*/
+	sigemptyset(&act.sa_mask);
+   act.sa_flags = 0;
+   act.sa_restorer = NULL;
+
+   sigaction ( SIGTERM, &act, NULL );
+
+	ioctl ( fd,  1, namebuf );
+
+	printf ( "iiSendPendingMail %p\n",        namebuf[0] );
+	printf ( "i2InitChannels %p\n",           namebuf[1] );
+	printf ( "i2QueueNeeds %p\n",             namebuf[2] );
+	printf ( "i2QueueCommands %p\n",          namebuf[3] );
+	printf ( "i2GetStatus %p\n",              namebuf[4] );
+	printf ( "i2Input %p\n",                  namebuf[5] );
+	printf ( "i2InputFlush %p\n",             namebuf[6] );
+	printf ( "i2Output %p\n",                 namebuf[7] );
+	printf ( "i2FlushOutput %p\n",            namebuf[8] );
+	printf ( "i2DrainWakeup %p\n",            namebuf[9] );
+	printf ( "i2DrainOutput %p\n",            namebuf[10] );
+	printf ( "i2OutputFree %p\n",             namebuf[11] );
+	printf ( "i2StripFifo %p\n",              namebuf[12] );
+	printf ( "i2StuffFifoBypass %p\n",        namebuf[13] );
+	printf ( "i2StuffFifoFlow %p\n",          namebuf[14] );
+	printf ( "i2StuffFifoInline %p\n",        namebuf[15] );
+	printf ( "i2ServiceBoard %p\n",           namebuf[16] );
+	printf ( "serviceOutgoingFifo %p\n",      namebuf[17] );
+	printf ( "ip2_init %p\n",                 namebuf[18] ); 
+	printf ( "ip2_init_board %p\n",           namebuf[19] ); 
+	printf ( "find_eisa_board %p\n",          namebuf[20] );  
+	printf ( "set_irq %p\n",                  namebuf[21] );  
+	printf ( "ex_details %p\n",               namebuf[22] );  
+	printf ( "ip2_interrupt %p\n",            namebuf[23] );  
+	printf ( "ip2_poll %p\n",                 namebuf[24] );  
+	printf ( "service_all_boards %p\n",        namebuf[25] );  
+	printf ( "do_input %p\n",                 namebuf[27] );  
+	printf ( "do_status %p\n",                namebuf[26] );  
+	printf ( "open_sanity_check %p\n",        namebuf[27] );  
+	printf ( "open_block_til_ready %p\n",     namebuf[28] );   
+	printf ( "ip2_open %p\n",                 namebuf[29] );  
+	printf ( "ip2_close %p\n",                namebuf[30] );  
+	printf ( "ip2_hangup %p\n",               namebuf[31] );  
+	printf ( "ip2_write %p\n",                namebuf[32] );  
+	printf ( "ip2_putchar %p\n",              namebuf[33] );  
+	printf ( "ip2_flush_chars %p\n",          namebuf[34] );  
+	printf ( "ip2_write_room %p\n",           namebuf[35] );  
+	printf ( "ip2_chars_in_buf %p\n",         namebuf[36] );  
+	printf ( "ip2_flush_buffer %p\n",         namebuf[37] );  
+	//printf ( "ip2_wait_until_sent %p\n",      namebuf[38] );  
+	printf ( "ip2_throttle %p\n",             namebuf[39] );  
+	printf ( "ip2_unthrottle %p\n",           namebuf[40] );  
+	printf ( "ip2_ioctl %p\n",                namebuf[41] );  
+	printf ( "get_modem_info %p\n",           namebuf[42] );  
+	printf ( "set_modem_info %p\n",           namebuf[43] );  
+	printf ( "get_serial_info %p\n",          namebuf[44] );  
+	printf ( "set_serial_info %p\n",          namebuf[45] );  
+	printf ( "ip2_set_termios %p\n",          namebuf[46] );  
+	printf ( "ip2_set_line_discipline %p\n",  namebuf[47] );  
+	printf ( "set_line_characteristics %p\n", namebuf[48] );  
+
+	printf("\n-------------------------\n");
+	printf("Start of trace\n");
+
+   while ( active ) {
+      cnt = read ( fd, &tbuf, sizeof tbuf );
+
+      if ( cnt ) {
+         if ( tbuf.wrap ) {
+            printf ( "\nTrace buffer: wrap=%d, strip=%d, stuff=%d\n",
+                     tbuf.wrap, tbuf.strip, tbuf.stuff );
+         }
+         for ( i = 0, bc.value = 0; i < cnt; ++i ) {
+				if ( !bc.hdr.codes ) {
+					td = tbuf.buf[i] - ts;
+					ts = tbuf.buf[i++];
+					bc.value = tbuf.buf[i];
+	
+					printf ( "\n(%d) Port %3d ", ts, bc.hdr.port );
+
+					fmt = kHex;
+
+					switch ( bc.hdr.cat )
+					{
+					case ITRC_INIT:
+						printf ( "Init       %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_OPEN:
+						printf ( "Open       %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_CLOSE:
+						printf ( "Close      %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_DRAIN:
+						printf ( "Drain      %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					case ITRC_IOCTL:
+						printf ( "Ioctl      %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_FLUSH:
+						printf ( "Flush      %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_STATUS:
+						printf ( "GetS       %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_HANGUP:
+						printf ( "Hangup     %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_INTR:
+						printf ( "*Intr      %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_SFLOW:
+						printf ( "SFlow      %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					case ITRC_SBCMD:
+						printf ( "Bypass CMD %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					case ITRC_SICMD:
+						printf ( "Inline CMD %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					case ITRC_MODEM:
+						printf ( "Modem      %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_INPUT:
+						printf ( "Input      %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_OUTPUT:
+						printf ( "Output     %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					case ITRC_PUTC:
+						printf ( "Put char   %d: ", bc.hdr.label );
+						fmt = kChar;
+						break;
+
+					case ITRC_QUEUE:
+						printf ( "Queue CMD  %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					case ITRC_STFLW:
+						printf ( "Stat Flow  %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					case ITRC_SFIFO:
+						printf ( "SFifo      %d: ", bc.hdr.label );
+						break;
+
+					case ITRC_VERIFY:
+						printf ( "Verfy      %d: ", bc.hdr.label );
+						fmt = kHex;
+						break;
+
+					case ITRC_WRITE:
+						printf ( "Write      %d: ", bc.hdr.label );
+						fmt = kChar;
+						break;
+
+					case ITRC_ERROR:
+						printf ( "ERROR      %d: ", bc.hdr.label );
+						fmt = kInt;
+						break;
+
+					default:
+						printf ( "%08x          ", tbuf.buf[i] );
+						break;
+					}
+				}
+				else 
+				{
+               --bc.hdr.codes;
+					switch ( fmt )
+					{
+					case kChar:
+						printf ( "%c (0x%02x) ", 
+							isprint ( tbuf.buf[i] ) ? tbuf.buf[i] : '.', tbuf.buf[i] );
+						break;
+					case kInt:
+						printf ( "%d ", tbuf.buf[i] );
+						break;
+
+					case kAddr:
+					case kHex:
+						printf ( "0x%x ", tbuf.buf[i] );
+						break;
+					}
+				}
+         }
+      }
+      fflush ( stdout );
+      timeout.tv_sec = 0;
+      timeout.tv_usec = 250;
+      select ( 0, NULL, NULL, NULL, &timeout );
+
+   }
+	printf("\n-------------------------\n");
+	printf("End of trace\n");
+
+   close ( fd );
+}
+
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.h linux/drivers/char/ip2/ip2trace.h
--- v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.h	Thu Aug 26 13:05:35 1999
+++ linux/drivers/char/ip2/ip2trace.h	Mon Apr 24 13:39:35 2000
@@ -9,7 +9,6 @@
 };
 
 #define ITRC_NO_PORT 	0xFF
-#define PORTN	(port->port_index)
 #define CHANN	(pCh->port_index)
 
 #define	ITRC_ERROR	'!'
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2.c linux/drivers/char/ip2.c
--- v2.3.99-pre5/linux/drivers/char/ip2.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/ip2.c	Tue Apr 25 17:52:01 2000
@@ -6,11 +6,22 @@
 //  __initdata should work as advertized
 //
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 
+#ifndef __init
+#define __init
+#endif
+#ifndef __initfunc
+#define __initfunc(a) a
+#endif
+#ifndef __initdata
+#define __initdata
+#endif
+
 #include "./ip2/ip2types.h"		
 #include "./ip2/fip_firm.h"		// the meat
 
@@ -18,15 +29,24 @@
 ip2_loadmain(int *, int  *, unsigned char *, int ); // ref into ip2main.c
 
 #ifdef MODULE
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#	define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#	include <linux/modversions.h>
+#endif
+
 static int io[IP2_MAX_BOARDS]= { 0,};
 static int irq[IP2_MAX_BOARDS] = { 0,}; 
 
-MODULE_AUTHOR("Doug McNash");
-MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
-MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
-MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
-MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
-MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
+#	if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+		MODULE_AUTHOR("Doug McNash");
+		MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+		MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+		MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
+		MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+		MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
+#	endif	/* LINUX_VERSION */
 
 
 //======================================================================
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c
--- v2.3.99-pre5/linux/drivers/char/ip2main.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/ip2main.c	Tue Apr 25 17:52:01 2000
@@ -10,21 +10,67 @@
 *   DESCRIPTION: Mainline code for the device driver
 *
 *******************************************************************************/
+// ToDo:
+//
+// Done:
+//
+// 1.2.9
+// Four box EX was barfing on >128k kmalloc, made structure smaller by
+// reducing output buffer size
+//
+// 1.2.8
+// Device file system support (MHW)
+//
+// 1.2.7 
+// Fixed
+// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules
+//
+// 1.2.6
+//Fixes DCD problems
+//	DCD was not reported when CLOCAL was set on call to TIOCMGET
+//
+//Enhancements:
+//	TIOCMGET requests and waits for status return
+//	No DSS interrupts enabled except for DCD when needed
+//
+// For internal use only
+//
+//#define IP2DEBUG_INIT
+//#define IP2DEBUG_OPEN
+//#define IP2DEBUG_WRITE
+//#define IP2DEBUG_READ
+//#define IP2DEBUG_IOCTL
+//#define IP2DEBUG_IPL
+
+//#define IP2DEBUG_TRACE
+//#define DEBUG_FIFO
+
 /************/
 /* Includes */
 /************/
-
 #include <linux/config.h>
-#include <linux/module.h>
+// Uncomment the following if you want it compiled with modversions
+#ifdef MODULE
+#	if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#		define MODVERSIONS
+#	endif
+#	ifdef MODVERSIONS
+#		include <linux/modversions.h>
+#	endif
+#endif
+
 #include <linux/version.h>
 
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
-
+#include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#ifdef	CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -50,13 +96,84 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <asm/serial.h>
-
-#include <asm/uaccess.h>
-#define		pcibios_strerror(status)	\
-	printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#	include <linux/vmalloc.h>
+#	include <linux/init.h>
+#	include <asm/serial.h>
+#else
+#	include <linux/bios32.h>
+#endif
+
+// These VERSION switches maybe inexact because I simply don't know
+// when the various features appeared in the 2.1.XX kernels.
+// They are good enough for 2.0 vs 2.2 and if you are fooling with
+// the 2.1.XX stuff then it would be trivial for you to fix.
+// Most of these macros were stolen from some other drivers
+// so blame them.
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,4)
+#	include <asm/segment.h>
+#	define GET_USER(error,value,addr) error = get_user(value,addr)
+#	define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
+#	define PUT_USER(error,value,addr) error = put_user(value,addr)
+#	define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
+
+#	if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,5)
+#		include <asm/uaccess.h>
+#		define		pcibios_strerror(status)	\
+					printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
+#	endif
+
+#else  /* 2.0.x and 2.1.x before 2.1.4 */
+
+#	define		proc_register_dynamic(a,b) proc_register(a,b) 
+
+#	define GET_USER(error,value,addr)					  \
+	do {									  \
+		error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
+		if (error == 0)							  \
+			value = get_user(addr);					  \
+	} while (0)
+
+#	define COPY_FROM_USER(error,dest,src,size)				  \
+	do {									  \
+		error = verify_area (VERIFY_READ, (void *) src, size);		  \
+		if (error == 0)							  \
+			memcpy_fromfs (dest, src, size);			  \
+	} while (0)
+
+#	define PUT_USER(error,value,addr)					   \
+	do {									   \
+		error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
+		if (error == 0)							   \
+			put_user (value, addr);					   \
+	} while (0)
+
+#	define COPY_TO_USER(error,dest,src,size)				  \
+	do {									  \
+		error = verify_area (VERIFY_WRITE, (void *) dest, size);		  \
+		if (error == 0)							  \
+			memcpy_tofs (dest, src, size);				  \
+	} while (0)
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+#define __init
+#define __initfunc(a) a
+#define __initdata
+#define ioremap(a,b) vremap((a),(b))
+#define iounmap(a) vfree((a))
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
+#define signal_pending(a) ((a)->signal & ~(a)->blocked)
+#define in_interrupt()	intr_count
+#endif
 
 #include "./ip2/ip2types.h"
 #include "./ip2/ip2trace.h"
@@ -84,12 +201,17 @@
 
 /* String constants to identify ourselves */
 static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.4";
+static char *pcVersion = "1.2.9";
 
 /* String constants for port names */
 static char *pcDriver_name   = "ip2";
-static char *pcTty    		 = "ttyf";
+#ifdef	CONFIG_DEVFS_FS
+static char *pcTty    		 = "ttf/%d";
+static char *pcCallout		 = "cuf/%d";
+#else
+static char *pcTty    		 = "ttyF";
 static char *pcCallout		 = "cuf";
+#endif
 static char *pcIpl    		 = "ip2ipl";
 
 /* Serial subtype definitions */
@@ -141,12 +263,15 @@
 static void ip2_wait_until_sent(PTTY,int);
 
 static void set_params (i2ChanStrPtr, struct termios *);
-static int get_modem_info(i2ChanStrPtr, unsigned int *);
 static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *);
 static int get_serial_info(i2ChanStrPtr, struct serial_struct *);
 static int set_serial_info(i2ChanStrPtr, struct serial_struct *);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+static int     ip2_ipl_read(struct inode *, char *, size_t , loff_t *);
+#else
 static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ;
+#endif
 static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *);
 static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);
 static int ip2_ipl_open(struct inode *, struct file *);
@@ -241,13 +366,14 @@
 
 /* Configuration area for modprobe */
 #ifdef MODULE
-MODULE_AUTHOR("Doug McNash");
-MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+#	if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+		MODULE_AUTHOR("Doug McNash");
+		MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+#	endif	/* LINUX_VERSION */
 #endif	/* MODULE */
 
 static int poll_only = 0;
 
-static int Pci_index = 0;
 static int Eisa_irq = 0;
 static int Eisa_slot = 0;
 
@@ -371,8 +497,6 @@
 #ifdef IP2DEBUG_INIT
 	printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
 #endif
-
-
 	/* Stop poll timer if we had one. */
 	if ( TimerOn ) {
 		del_timer ( &PollTimer );
@@ -382,7 +506,7 @@
 	/* Reset the boards we have. */
 	for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
 		if ( i2BoardPtrTable[i] ) {
-			iiReset ( i2BoardPtrTable[i] );
+			iiReset( i2BoardPtrTable[i] );
 		}
 	}
 
@@ -392,6 +516,10 @@
 			iiResetDelay( i2BoardPtrTable[i] );
 			/* free io addresses and Tibet */
 			release_region( ip2config.addr[i], 8 );
+#ifdef	CONFIG_DEVFS_FS
+			devfs_unregister (i2BoardPtrTable[i]->devfs_ipl_handle);
+			devfs_unregister (i2BoardPtrTable[i]->devfs_stat_handle);
+#endif
 		}
 		/* Disable and remove interrupt handler. */
 		if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {	
@@ -405,7 +533,12 @@
 	if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) {
 		printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err);
 	}
-	if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
+#ifdef	CONFIG_DEVFS_FS
+	if ( ( err = devfs_unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) )
+#else
+	if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) )
+#endif
+	{
 		printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
 	}
 	remove_proc_entry("ip2mem", &proc_root);
@@ -450,9 +583,14 @@
 int __init
 old_ip2_init(void)
 {
+#ifdef	CONFIG_DEVFS_FS
+	static devfs_handle_t devfs_handle = NULL;
+	int j, box;
+#endif
 	int i;
 	int err;
 	int status = 0;
+	static int loaded = 0;
 	i2eBordStrPtr pB = NULL;
 	int rc = -1;
 
@@ -463,6 +601,15 @@
 	/* Announce our presence */
 	printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
 
+	// ip2 can be unloaded and reloaded for no good reason
+	// we can't let that happen here or bad things happen
+	// second load hoses board but not system - fixme later
+	if (loaded) {
+		printk( KERN_INFO "Still loaded\n" );
+		return 0;
+	}
+	loaded++;
+
 	/* if all irq config is zero we shall poll_only */
 	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
 		poll_only |= ip2config.irq[i];
@@ -502,11 +649,14 @@
 			break;
 		case PCI:
 #ifdef CONFIG_PCI
-			if (pci_present()) {
-				struct pci_dev *pci_dev_i = NULL;
-				pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
-							  PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
-				if (pci_dev_i != NULL) {
+#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
+			if (pcibios_present()) {
+				unsigned char pci_bus, pci_devfn;
+				int Pci_index = 0;
+				status = pcibios_find_device(PCI_VENDOR_ID_COMPUTONE,
+							  PCI_DEVICE_ID_COMPUTONE_IP2EX, Pci_index,
+							  &pci_bus, &pci_devfn);
+				if (status == 0) {
 					unsigned int addr;
 					unsigned char pci_irq;
 
@@ -517,6 +667,41 @@
 					 * one.
 					 */
 					++Pci_index;
+
+					pcibios_read_config_dword(pci_bus, pci_devfn,
+								  PCI_BASE_ADDRESS_1, &addr);
+					if ( addr & 1 ) {
+						ip2config.addr[i]=(USHORT)(addr&0xfffe);
+					} else {
+						printk( KERN_ERR "IP2: PCI I/O address error\n");
+					}
+					pcibios_read_config_byte(pci_bus, pci_devfn,
+								  PCI_INTERRUPT_LINE, &pci_irq);
+
+					if (!is_valid_irq(pci_irq)) {
+						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
+						pci_irq = 0;
+					}
+					ip2config.irq[i] = pci_irq;
+				} else {	// ann error
+					ip2config.addr[i] = 0;
+					if (status == PCIBIOS_DEVICE_NOT_FOUND) {
+						printk( KERN_ERR "IP2: PCI board %d not found\n", i );
+					} else {
+						pcibios_strerror(status);
+					}
+				} 
+			} 
+#else /* LINUX_VERSION_CODE > 2.1.99 */
+			if (pci_present()) {
+				struct pci_dev *pci_dev_i = NULL;
+				pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
+							  PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
+				if (pci_dev_i != NULL) {
+					unsigned int addr;
+					unsigned char pci_irq;
+
+					ip2config.type[i] = PCI;
 					status =
 					pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
 					if ( addr & 1 ) {
@@ -541,6 +726,7 @@
 					}
 				} 
 			} 
+#endif	/* ! 2_0_X */
 #else
 			printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
 			printk( KERN_ERR "IP2: configured in this kernel.\n");
@@ -591,8 +777,10 @@
 	/* Initialise the relevant fields. */
 	ip2_tty_driver.magic                = TTY_DRIVER_MAGIC;
 	ip2_tty_driver.name                 = pcTty;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
 	ip2_tty_driver.driver_name          = pcDriver_name;
 	ip2_tty_driver.read_proc          	= ip2_read_proc;
+#endif
 	ip2_tty_driver.major                = IP2_TTY_MAJOR;
 	ip2_tty_driver.minor_start          = 0;
 	ip2_tty_driver.num                  = IP2_MAX_PORTS;
@@ -600,7 +788,11 @@
 	ip2_tty_driver.subtype              = SERIAL_TYPE_NORMAL;
 	ip2_tty_driver.init_termios         = tty_std_termios;
 	ip2_tty_driver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+#ifdef	CONFIG_DEVFS_FS
+	ip2_tty_driver.flags                = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+#else
 	ip2_tty_driver.flags                = TTY_DRIVER_REAL_RAW;
+#endif
 	ip2_tty_driver.refcount             = &ref_count;
 	ip2_tty_driver.table                = TtyTable;
 	ip2_tty_driver.termios              = Termios;
@@ -629,8 +821,10 @@
 	 */
 	ip2_callout_driver         = ip2_tty_driver;
 	ip2_callout_driver.name    = pcCallout;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
 	ip2_callout_driver.driver_name = pcDriver_name;
 	ip2_callout_driver.read_proc  = NULL;
+#endif
 	ip2_callout_driver.major   = IP2_CALLOUT_MAJOR;
 	ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
@@ -646,7 +840,12 @@
 		printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err);
 	} else
 	/* Register the IPL driver. */
-	if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
+#ifdef	CONFIG_DEVFS_FS
+	if (( err = devfs_register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl )))
+#else
+	if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) )
+#endif
+	{
 		printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
 	} else
 	/* Register the read_procmem thing */
@@ -660,10 +859,54 @@
 		/* Register the interrupt handler or poll handler, depending upon the
 		 * specified interrupt.
 		 */
+#ifdef	CONFIG_DEVFS_FS
+		if (!devfs_handle)
+			devfs_handle = devfs_mk_dir (NULL, "ip2", 3, NULL);
+#endif
+
 		for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+#ifdef	CONFIG_DEVFS_FS
+			char name[16];
+#endif
+
 			if ( 0 == ip2config.addr[i] ) {
 				continue;
 			}
+
+#ifdef	CONFIG_DEVFS_FS
+			sprintf( name, "ipl%d", i );
+			i2BoardPtrTable[i]->devfs_ipl_handle =
+				devfs_register (devfs_handle, name, 0,
+					DEVFS_FL_NONE,
+					IP2_IPL_MAJOR, 4 * i,
+					S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
+					0, 0, &ip2_ipl, NULL);
+
+			sprintf( name, "stat%d", i );
+			i2BoardPtrTable[i]->devfs_stat_handle =
+				devfs_register (devfs_handle, name, 0,
+					DEVFS_FL_NONE,
+					IP2_IPL_MAJOR, 4 * i + 1,
+					S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
+					0, 0, &ip2_ipl, NULL);
+
+			for ( box = 0; box < ABS_MAX_BOXES; ++box )
+			{
+			    for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
+			    {
+				if ( pB->i2eChannelMap[box] & (1 << j) )
+				{
+				    tty_register_devfs(&ip2_tty_driver,
+					0, j + ABS_BIGGEST_BOX *
+						(box+i*ABS_MAX_BOXES));
+				    tty_register_devfs(&ip2_callout_driver,
+					0, j + ABS_BIGGEST_BOX *
+						(box+i*ABS_MAX_BOXES));
+				}
+			    }
+			}
+#endif
+
 			if (poll_only) {
 					ip2config.irq[i] = CIR_POLL;
 			}
@@ -932,7 +1175,6 @@
 static void
 set_irq( int boardnum, int boardIrq )
 {
-	i2ChanStrPtr pCh;
 	unsigned char tempCommand[16];
 	i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
 	unsigned long flags;
@@ -946,8 +1188,6 @@
 	 * is done.  If polling we must send 0 as the interrupt parameter.
 	 */
 
-	pCh = (i2ChanStrPtr) pB->i2eChannelPtr;
-
 	// We will get an interrupt here at the end of this function
 
 	iiDisableMailIrq(pB);
@@ -1129,7 +1369,7 @@
 	unsigned long flags;
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace(PORTN, ITRC_INPUT, 21, 0 );
+	ip2trace(CHANN, ITRC_INPUT, 21, 0 );
 #endif
 	// Data input
 	if ( pCh->pTTY != NULL ) {
@@ -1141,7 +1381,7 @@
 			READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
 	} else {
 #ifdef IP2DEBUG_TRACE
-		ip2trace(PORTN, ITRC_INPUT, 22, 0 );
+		ip2trace(CHANN, ITRC_INPUT, 22, 0 );
 #endif
 		i2InputFlush( pCh );
 	}
@@ -1168,7 +1408,7 @@
 	status =  i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_STATUS, 21, 1, status );
+	ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
 #endif
 
 	if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
@@ -1230,7 +1470,7 @@
 	}
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_STATUS, 26, 0 );
+	ip2trace (CHANN, ITRC_STATUS, 26, 0 );
 #endif
 }
 
@@ -1305,11 +1545,8 @@
 	open_sanity_check ( pCh, pCh->pMyBord );
 #endif
 
-	i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
+	i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
 	pCh->dataSetOut |= (I2_DTR | I2_RTS);
-	i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
-	i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, 
-				CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
 	serviceOutgoingFifo( pCh->pMyBord );
 
 	/* Block here until the port is ready (per serial and istallion) */
@@ -1401,7 +1638,7 @@
 		printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
 #endif
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE),
+		ip2trace (CHANN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE),
 								(pCh->flags & ASYNC_CLOSING) );
 #endif
 		/* check for signal */
@@ -1413,7 +1650,7 @@
 	}
 	--pCh->wopen; //why count?
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_OPEN, 4, 0 );
+	ip2trace (CHANN, ITRC_OPEN, 4, 0 );
 #endif
 	if (rc != 0 ) {
 		return rc;
@@ -1452,7 +1689,7 @@
 	serviceOutgoingFifo( pCh->pMyBord );
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_OPEN, ITRC_RETURN, 0 );
+	ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
 #endif
 	return 0;
 }
@@ -1477,7 +1714,7 @@
 	}
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_CLOSE, ITRC_ENTER, 0 );
+	ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
 #endif
 
 #ifdef IP2DEBUG_OPEN
@@ -1488,14 +1725,14 @@
 		MOD_DEC_USE_COUNT;
 
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_CLOSE, 2, 1, 2 );
+		ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
 #endif
 		return;
 	}
 	if ( tty->count > 1 ) { /* not the last close */
 		MOD_DEC_USE_COUNT;
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_CLOSE, 2, 1, 3 );
+		ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
 #endif
 		return;
 	}
@@ -1528,14 +1765,13 @@
 	i2InputFlush( pCh );
 
 	/* disable DSS reporting */
-	i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
+	i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
+				CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
 	if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
 		i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
 		pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
 		i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
 	}
-	i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, 
-				CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
 
 	serviceOutgoingFifo ( pCh->pMyBord );
 
@@ -1565,7 +1801,7 @@
 	MOD_DEC_USE_COUNT;
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
+	ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
 #endif
 	return;
 }
@@ -1585,7 +1821,7 @@
 	i2ChanStrPtr  pCh = tty->driver_data;
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_HANGUP, ITRC_ENTER, 0 );
+	ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
 #endif
 
 	ip2_flush_buffer(tty);
@@ -1610,7 +1846,7 @@
 	wake_up_interruptible ( &pCh->open_wait );
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_HANGUP, ITRC_RETURN, 0 );
+	ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
 #endif
 }
 
@@ -1640,7 +1876,7 @@
 	unsigned long flags;
 
 #ifdef IP2DEBUG_TRACE
-   ip2trace (PORTN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
+   ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
 #endif
 
 	/* Flush out any buffered data left over from ip2_putchar() calls. */
@@ -1652,7 +1888,7 @@
 	WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
 
 #ifdef IP2DEBUG_TRACE
-   ip2trace (PORTN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
+   ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
 #endif
 	return bytesSent > 0 ? bytesSent : 0;
 }
@@ -1674,7 +1910,7 @@
 	unsigned long flags;
 
 #ifdef IP2DEBUG_TRACE
-//	ip2trace (PORTN, ITRC_PUTC, ITRC_ENTER, 1, ch );
+//	ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
 #endif
 
 	WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
@@ -1686,7 +1922,7 @@
 		WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
 
 #ifdef IP2DEBUG_TRACE
-//	ip2trace (PORTN, ITRC_PUTC, ITRC_RETURN, 1, ch );
+//	ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
 #endif
 }
 
@@ -1708,7 +1944,7 @@
 	WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
 	if ( pCh->Pbuf_stuff ) {
 #ifdef IP2DEBUG_TRACE
-//	ip2trace (PORTN, ITRC_PUTC, 10, 1, strip );
+//	ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
 #endif
 		//
 		// We may need to restart i2Output if it does not fullfill this request
@@ -1742,7 +1978,7 @@
 	READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_WRITE, 11, 1, bytesFree );
+	ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
 #endif
 
 	return ((bytesFree > 0) ? bytesFree : 0);
@@ -1764,7 +2000,7 @@
 	int rc;
 	unsigned long flags;
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
+	ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
 #endif
 #ifdef IP2DEBUG_WRITE
 	printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
@@ -1796,7 +2032,7 @@
 	unsigned long flags;
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_FLUSH, ITRC_ENTER, 0 );
+	ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
 #endif
 #ifdef IP2DEBUG_WRITE
 	printk (KERN_DEBUG "IP2: flush buffer\n" );
@@ -1807,7 +2043,7 @@
 	i2FlushOutput( pCh );
 	ip2_owake(tty);
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_FLUSH, ITRC_RETURN, 0 );
+	ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
 #endif
 }
 
@@ -1943,17 +2179,18 @@
 static int
 ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
 {
-	i2ChanStrPtr  pCh = DevTable[MINOR(tty->device)];
+	i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
 	struct async_icount cprev, cnow;	/* kernel counter temps */
 	struct serial_icounter_struct *p_cuser;	/* user space */
 	int rc = 0;
+	unsigned long flags;
 
 	if ( pCh == NULL ) {
 		return -ENODEV;
 	}
 
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
+	ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
 #endif
 
 #ifdef IP2DEBUG_IOCTL
@@ -1963,7 +2200,7 @@
 	switch(cmd) {
 	case TIOCGSERIAL:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 2, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
 #endif
 		rc = get_serial_info(pCh, (struct serial_struct *) arg);
 		if (rc)
@@ -1972,7 +2209,7 @@
 
 	case TIOCSSERIAL:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 3, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
 #endif
 		rc = set_serial_info(pCh, (struct serial_struct *) arg);
 		if (rc)
@@ -2010,7 +2247,7 @@
 	case TCSBRK:   /* SVID version: non-zero arg --> no break */
 		rc = tty_check_change(tty);
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 4, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
 #endif
 		if (!rc) {
 			ip2_wait_until_sent(tty,0);
@@ -2024,7 +2261,7 @@
 	case TCSBRKP:  /* support for POSIX tcsendbreak() */
 		rc = tty_check_change(tty);
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 5, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
 #endif
 		if (!rc) {
 			ip2_wait_until_sent(tty,0);
@@ -2036,18 +2273,18 @@
 
 	case TIOCGSOFTCAR:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 6, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
 #endif
-			rc=put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+			PUT_USER(rc,C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
 		if (rc)	
 			return rc;
 	break;
 
 	case TIOCSSOFTCAR:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 7, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
 #endif
-		rc=get_user(arg,(unsigned long *) arg);
+		GET_USER(rc,arg,(unsigned long *) arg);
 		if (rc) 
 			return rc;
 		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
@@ -2057,18 +2294,37 @@
 
 	case TIOCMGET:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 8, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 8, 1, rc );
 #endif
-		rc = get_modem_info(pCh, (unsigned int *) arg);
-		if (rc) 
-			return rc;
+/*
+	FIXME - the following code is causing a NULL pointer dereference in
+	2.3.51 in an interrupt handler.  It's suppose to prompt the board
+	to return the DSS signal status immediately.  Why doesn't it do
+	the same thing in 2.2.14?
+*/
+/*
+		i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
+		serviceOutgoingFifo( pCh->pMyBord );
+		interruptible_sleep_on(&pCh->dss_now_wait);
+		if (signal_pending(current)) {
+			return -EINTR;
+		}
+*/
+		PUT_USER(rc,
+				    ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
+				  | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
+				  | ((pCh->dataSetIn  & I2_DCD) ? TIOCM_CAR : 0)
+				  | ((pCh->dataSetIn  & I2_RI)  ? TIOCM_RNG : 0)
+				  | ((pCh->dataSetIn  & I2_DSR) ? TIOCM_DSR : 0)
+				  | ((pCh->dataSetIn  & I2_CTS) ? TIOCM_CTS : 0),
+				(unsigned int *) arg);
 		break;
 
 	case TIOCMBIS:
 	case TIOCMBIC:
 	case TIOCMSET:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 9, 0 );
+		ip2trace (CHANN, ITRC_IOCTL, 9, 0 );
 #endif
 		rc = set_modem_info(pCh, cmd, (unsigned int *) arg);
 		break;
@@ -2079,24 +2335,34 @@
 	 * for masking). Caller should use TIOCGICOUNT to see which one it was
 	 */
 	case TIOCMIWAIT:
+		save_flags(flags);cli();
 		cprev = pCh->icount;	 /* note the counters on entry */
+		restore_flags(flags);
+		i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4, 
+						CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
+		serviceOutgoingFifo( pCh->pMyBord );
 		for(;;) {
 #ifdef IP2DEBUG_TRACE
-			ip2trace (PORTN, ITRC_IOCTL, 10, 0 );
+			ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
 #endif
 			interruptible_sleep_on(&pCh->delta_msr_wait);
+#ifdef IP2DEBUG_TRACE
+			ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
+#endif
 			/* see if a signal did it */
 			if (signal_pending(current)) {
 				rc = -ERESTARTSYS;
 				break;
 			}
+			save_flags(flags);cli();
 			cnow = pCh->icount; /* atomic copy */
+			restore_flags(flags);
 			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-			   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+				cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
 				rc =  -EIO; /* no change => rc */
 				break;
 			}
-			if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
 			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
 			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
 			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
@@ -2105,7 +2371,13 @@
 			}
 			cprev = cnow;
 		}
-		/* NOTREACHED */
+		i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3, 
+						 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
+		if ( ! (pCh->flags	& ASYNC_CHECK_CD)) {
+			i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
+		}
+		serviceOutgoingFifo( pCh->pMyBord );
+		return rc;
 		break;
 
 	/*
@@ -2118,14 +2390,23 @@
 	 */
 	case TIOCGICOUNT:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 11, 1, rc );
+		ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
 #endif
+		save_flags(flags);cli();
 		cnow = pCh->icount;
+		restore_flags(flags);
 		p_cuser = (struct serial_icounter_struct *) arg;
-		put_user(cnow.cts, &p_cuser->cts);
-		put_user(cnow.dsr, &p_cuser->dsr);
-		put_user(cnow.rng, &p_cuser->rng);
-		put_user(cnow.dcd, &p_cuser->dcd);
+		PUT_USER(rc,cnow.cts, &p_cuser->cts);
+		PUT_USER(rc,cnow.dsr, &p_cuser->dsr);
+		PUT_USER(rc,cnow.rng, &p_cuser->rng);
+		PUT_USER(rc,cnow.dcd, &p_cuser->dcd);
+		PUT_USER(rc,cnow.rx, &p_cuser->rx);
+		PUT_USER(rc,cnow.tx, &p_cuser->tx);
+		PUT_USER(rc,cnow.frame, &p_cuser->frame);
+		PUT_USER(rc,cnow.overrun, &p_cuser->overrun);
+		PUT_USER(rc,cnow.parity, &p_cuser->parity);
+		PUT_USER(rc,cnow.brk, &p_cuser->brk);
+		PUT_USER(rc,cnow.buf_overrun, &p_cuser->buf_overrun);
 		break;
 
 	/*
@@ -2142,43 +2423,16 @@
 
 	default:
 #ifdef IP2DEBUG_TRACE
-		ip2trace (PORTN, ITRC_IOCTL, 12, 0 );
+		ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
 #endif
 		rc =  -ENOIOCTLCMD;
 		break;
 	}
 #ifdef IP2DEBUG_TRACE
-	ip2trace (PORTN, ITRC_IOCTL, ITRC_RETURN, 0 );
+	ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
 #endif
 	return rc;
 }
-/******************************************************************************/
-/* Function:   get_modem_info()                                               */
-/* Parameters: Pointer to channel structure                                   */
-/*             Pointer to destination for data                                */
-/* Returns:    Nothing                                                        */
-/*                                                                            */
-/* Description:                                                               */
-/* This returns the current settings of the dataset signal inputs to the user */
-/* program.                                                                   */
-/******************************************************************************/
-static int
-get_modem_info(i2ChanStrPtr pCh, unsigned int *value)
-{
-	unsigned short status;
-	unsigned int result;
-	int rc;
-
-	status = pCh->dataSetIn;	// snapshot settings
-	result = ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
-		  | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
-		  | ((status  & I2_DCD) ? TIOCM_CAR : 0)
-		  | ((status  & I2_RI) ? TIOCM_RNG : 0)
-		  | ((status  & I2_DSR) ? TIOCM_DSR : 0)
-		  | ((status  & I2_CTS) ? TIOCM_CTS : 0);
-	rc=put_user(result,value);
-	return rc;
-}
 
 /******************************************************************************/
 /* Function:   set_modem_info()                                               */
@@ -2197,7 +2451,7 @@
 	int rc;
 	unsigned int arg;
 
-	rc=get_user(arg,value);
+	GET_USER(rc,arg,value);
 	if (rc)
 		return rc;
 	switch(cmd) {
@@ -2258,7 +2512,7 @@
 get_serial_info ( i2ChanStrPtr pCh, struct serial_struct *retinfo )
 {
 	struct serial_struct tmp;
-	int rc=0;
+	int rc;
 
 	if ( !retinfo ) {
 		return -EFAULT;
@@ -2279,9 +2533,8 @@
 	tmp.close_delay = pCh->ClosingDelay;
 	tmp.closing_wait = pCh->ClosingWaitTime;
 	tmp.custom_divisor = pCh->BaudDivisor;
-   	if(copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
-   		rc= -EFAULT;
-	return rc;
+   	COPY_TO_USER(rc,retinfo,&tmp,sizeof(*retinfo));
+   return rc;
 }
 
 /******************************************************************************/
@@ -2305,7 +2558,7 @@
 	if ( !new_info ) {
 		return -EFAULT;
 	}
-	rc=copy_from_user(&ns, new_info, sizeof (ns) );
+	COPY_FROM_USER(rc, &ns, new_info, sizeof (ns) );
 	if (rc) {
 		return rc;
 	}
@@ -2631,6 +2884,7 @@
 		i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
 	}
 	if (cflag & CLOCAL) {
+		// Status reporting fails for DCD if this is off
 		i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
 		pCh->flags &= ~ASYNC_CHECK_CD;
 	} else {
@@ -2670,10 +2924,16 @@
 /******************************************************************************/
 
 static 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+int
+ip2_ipl_read(struct inode *pInode, char *pData, size_t count, loff_t *off )
+	unsigned int minor = MINOR( pInode->i_rdev );
+#else
 ssize_t
 ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off )
 {
 	unsigned int minor = MINOR( pFile->f_dentry->d_inode->i_rdev );
+#endif
 	int rc = 0;
 
 #ifdef IP2DEBUG_IPL
@@ -2707,9 +2967,8 @@
 DumpFifoBuffer ( char *pData, int count )
 {
 #ifdef DEBUG_FIFO
-	int rc=0;
-	if(copy_to_user(pData, DBGBuf, count))
-		rc=-EFAULT;
+	int rc;
+	COPY_TO_USER(rc, pData, DBGBuf, count);
 
 	printk(KERN_DEBUG "Last index %d\n", I );
 
@@ -2730,10 +2989,10 @@
 	if ( count < (sizeof(int) * 6) ) {
 		return -EIO;
 	}
-	put_user(tracewrap, pIndex );
-	put_user(TRACEMAX, ++pIndex );
-	put_user(tracestrip, ++pIndex );
-	put_user(tracestuff, ++pIndex );
+	PUT_USER(rc, tracewrap, pIndex );
+	PUT_USER(rc, TRACEMAX, ++pIndex );
+	PUT_USER(rc, tracestrip, ++pIndex );
+	PUT_USER(rc, tracestuff, ++pIndex );
 	pData += sizeof(int) * 6;
 	count -= sizeof(int) * 6;
 
@@ -2746,21 +3005,21 @@
 	}
 	chunk = TRACEMAX - tracestrip;
 	if ( dumpcount > chunk ) {
-		rc=copy_to_user(pData, &tracebuf[tracestrip],
-			      chunk * sizeof(tracebuf[0]) )?-EFAULT:0;
+		COPY_TO_USER(rc, pData, &tracebuf[tracestrip],
+			      chunk * sizeof(tracebuf[0]) );
 		pData += chunk * sizeof(tracebuf[0]);
 		tracestrip = 0;
 		chunk = dumpcount - chunk;
 	} else {
 		chunk = dumpcount;
 	}
-	rc=copy_to_user(pData, &tracebuf[tracestrip],
-		      chunk * sizeof(tracebuf[0]) )?-EFAULT:0
+	COPY_TO_USER(rc, pData, &tracebuf[tracestrip],
+		      chunk * sizeof(tracebuf[0]) );
 	tracestrip += chunk;
 	tracewrap = 0;
 
-	put_user(tracestrip, ++pIndex );
-	put_user(tracestuff, ++pIndex );
+	PUT_USER(rc, tracestrip, ++pIndex );
+	PUT_USER(rc, tracestuff, ++pIndex );
 
 	return dumpcount;
 #else
@@ -2824,16 +3083,15 @@
 	case 13:
 		switch ( cmd ) {
 		case 64:	/* Driver - ip2stat */
-			put_user(ref_count, pIndex++ );
-			put_user(irq_counter, pIndex++  );
-			put_user(bh_counter, pIndex++  );
+			PUT_USER(rc, ref_count, pIndex++ );
+			PUT_USER(rc, irq_counter, pIndex++  );
+			PUT_USER(rc, bh_counter, pIndex++  );
 			break;
 
 		case 65:	/* Board  - ip2stat */
 			if ( pB ) {
-				if(copy_to_user((char*)arg, (char*)pB, sizeof(i2eBordStr) ))
-					rc=-EFAULT;
-				put_user(INB(pB->i2eStatus),
+				COPY_TO_USER(rc, (char*)arg, (char*)pB, sizeof(i2eBordStr) );
+				PUT_USER(rc, INB(pB->i2eStatus),
 					(ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
 			} else {
 				rc = -ENODEV;
@@ -2844,8 +3102,7 @@
 			pCh = DevTable[cmd];
 			if ( pCh )
 			{
-				if(copy_to_user((char*)arg, (char*)pCh, sizeof(i2ChanStr) ))
-					rc = -EFAULT;
+				COPY_TO_USER(rc, (char*)arg, (char*)pCh, sizeof(i2ChanStr) );
 			} else {
 				rc = cmd < 64 ? -ENODEV : -EINVAL;
 			}
@@ -2857,61 +3114,60 @@
 		break;
 	case 3:	    // Trace device
 		if ( cmd == 1 ) {
-			put_user(iiSendPendingMail, pIndex++ );
-			put_user(i2InitChannels, pIndex++ );
-			put_user(i2QueueNeeds, pIndex++ );
-			put_user(i2QueueCommands, pIndex++ );
-			put_user(i2GetStatus, pIndex++ );
-			put_user(i2Input, pIndex++ );
-			put_user(i2InputFlush, pIndex++ );
-			put_user(i2Output, pIndex++ );
-			put_user(i2FlushOutput, pIndex++ );
-			put_user(i2DrainWakeup, pIndex++ );
-			put_user(i2DrainOutput, pIndex++ );
-			put_user(i2OutputFree, pIndex++ );
-			put_user(i2StripFifo, pIndex++ );
-			put_user(i2StuffFifoBypass, pIndex++ );
-			put_user(i2StuffFifoFlow, pIndex++ );
-			put_user(i2StuffFifoInline, pIndex++ );
-			put_user(i2ServiceBoard, pIndex++ );
-			put_user(serviceOutgoingFifo, pIndex++ );
-			// put_user(ip2_init, pIndex++ );
-			put_user(ip2_init_board, pIndex++ );
-			put_user(find_eisa_board, pIndex++ );
-			put_user(set_irq, pIndex++ );
-			put_user(ip2_interrupt, pIndex++ );
-			put_user(ip2_poll, pIndex++ );
-			put_user(service_all_boards, pIndex++ );
-			put_user(do_input, pIndex++ );
-			put_user(do_status, pIndex++ );
+			PUT_USER(rc, iiSendPendingMail, pIndex++ );
+			PUT_USER(rc, i2InitChannels, pIndex++ );
+			PUT_USER(rc, i2QueueNeeds, pIndex++ );
+			PUT_USER(rc, i2QueueCommands, pIndex++ );
+			PUT_USER(rc, i2GetStatus, pIndex++ );
+			PUT_USER(rc, i2Input, pIndex++ );
+			PUT_USER(rc, i2InputFlush, pIndex++ );
+			PUT_USER(rc, i2Output, pIndex++ );
+			PUT_USER(rc, i2FlushOutput, pIndex++ );
+			PUT_USER(rc, i2DrainWakeup, pIndex++ );
+			PUT_USER(rc, i2DrainOutput, pIndex++ );
+			PUT_USER(rc, i2OutputFree, pIndex++ );
+			PUT_USER(rc, i2StripFifo, pIndex++ );
+			PUT_USER(rc, i2StuffFifoBypass, pIndex++ );
+			PUT_USER(rc, i2StuffFifoFlow, pIndex++ );
+			PUT_USER(rc, i2StuffFifoInline, pIndex++ );
+			PUT_USER(rc, i2ServiceBoard, pIndex++ );
+			PUT_USER(rc, serviceOutgoingFifo, pIndex++ );
+			// PUT_USER(rc, ip2_init, pIndex++ );
+			PUT_USER(rc, ip2_init_board, pIndex++ );
+			PUT_USER(rc, find_eisa_board, pIndex++ );
+			PUT_USER(rc, set_irq, pIndex++ );
+			PUT_USER(rc, ip2_interrupt, pIndex++ );
+			PUT_USER(rc, ip2_poll, pIndex++ );
+			PUT_USER(rc, service_all_boards, pIndex++ );
+			PUT_USER(rc, do_input, pIndex++ );
+			PUT_USER(rc, do_status, pIndex++ );
 #ifndef IP2DEBUG_OPEN
-			put_user(0, pIndex++ );
+			PUT_USER(rc, 0, pIndex++ );
 #else
-			put_user(open_sanity_check, pIndex++ );
+			PUT_USER(rc, open_sanity_check, pIndex++ );
 #endif
-			put_user(ip2_open, pIndex++ );
-			put_user(ip2_close, pIndex++ );
-			put_user(ip2_hangup, pIndex++ );
-			put_user(ip2_write, pIndex++ );
-			put_user(ip2_putchar, pIndex++ );
-			put_user(ip2_flush_chars, pIndex++ );
-			put_user(ip2_write_room, pIndex++ );
-			put_user(ip2_chars_in_buf, pIndex++ );
-			put_user(ip2_flush_buffer, pIndex++ );
-
-			//put_user(ip2_wait_until_sent, pIndex++ );
-			put_user(0, pIndex++ );
-
-			put_user(ip2_throttle, pIndex++ );
-			put_user(ip2_unthrottle, pIndex++ );
-			put_user(ip2_ioctl, pIndex++ );
-			put_user(get_modem_info, pIndex++ );
-			put_user(set_modem_info, pIndex++ );
-			put_user(get_serial_info, pIndex++ );
-			put_user(set_serial_info, pIndex++ );
-			put_user(ip2_set_termios, pIndex++ );
-			put_user(ip2_set_line_discipline, pIndex++ );
-			put_user(set_params, pIndex++ );
+			PUT_USER(rc, ip2_open, pIndex++ );
+			PUT_USER(rc, ip2_close, pIndex++ );
+			PUT_USER(rc, ip2_hangup, pIndex++ );
+			PUT_USER(rc, ip2_write, pIndex++ );
+			PUT_USER(rc, ip2_putchar, pIndex++ );
+			PUT_USER(rc, ip2_flush_chars, pIndex++ );
+			PUT_USER(rc, ip2_write_room, pIndex++ );
+			PUT_USER(rc, ip2_chars_in_buf, pIndex++ );
+			PUT_USER(rc, ip2_flush_buffer, pIndex++ );
+
+			//PUT_USER(rc, ip2_wait_until_sent, pIndex++ );
+			PUT_USER(rc, 0, pIndex++ );
+
+			PUT_USER(rc, ip2_throttle, pIndex++ );
+			PUT_USER(rc, ip2_unthrottle, pIndex++ );
+			PUT_USER(rc, ip2_ioctl, pIndex++ );
+			PUT_USER(rc, set_modem_info, pIndex++ );
+			PUT_USER(rc, get_serial_info, pIndex++ );
+			PUT_USER(rc, set_serial_info, pIndex++ );
+			PUT_USER(rc, ip2_set_termios, pIndex++ );
+			PUT_USER(rc, ip2_set_line_discipline, pIndex++ );
+			PUT_USER(rc, set_params, pIndex++ );
 		} else {
 			rc = -EINVAL;
 		}
@@ -3150,7 +3406,7 @@
 	if (off >= len+begin)
 		return 0;
 
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
  }
  
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c
--- v2.3.99-pre5/linux/drivers/char/joystick/joystick.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/joystick/joystick.c	Mon Apr 24 17:55:15 2000
@@ -516,7 +516,9 @@
 
 	MOD_INC_USE_COUNT;
 
-	if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {
+	new = kmalloc(sizeof(struct js_list), GFP_KERNEL);
+	if (!new) {
+		jd->close(jd);
 		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.3.99-pre5/linux/drivers/char/misc.c	Mon Mar 27 08:08:23 2000
+++ linux/drivers/char/misc.c	Thu Apr 13 07:54:32 2000
@@ -138,12 +138,12 @@
  *	@misc: device structure
  *	
  *	Register a miscellaneous device with the kernel. If the minor
- *	number is set to MISC_DYNAMIC_MINOR a minor number is assigned
+ *	number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
  *	and placed in the minor field of the structure. For other cases
  *	the minor number requested is used.
  *
  *	The structure passed is linked into the kernel and may not be
- *	destroyed until it has been unregistered
+ *	destroyed until it has been unregistered.
  *
  *	A zero is returned on success and a negative errno code for
  *	failure.
@@ -195,7 +195,7 @@
  *	@misc: device to unregister
  *
  *	Unregister a miscellaneous device that was previously
- *	successfully registered with misc_register. Success
+ *	successfully registered with misc_register(). Success
  *	is indicated by a zero return, a negative errno code
  *	indicates an error.
  */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.3.99-pre5/linux/drivers/char/msp3400.c	Tue Mar  7 14:32:25 2000
+++ linux/drivers/char/msp3400.c	Fri Apr 21 16:08:45 2000
@@ -34,6 +34,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -46,7 +47,7 @@
 #include <linux/videodev.h>
 #include <asm/semaphore.h>
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #include <asm/pgtable.h>
 #include <linux/smp_lock.h>
 #endif
@@ -59,7 +60,6 @@
 #define WAIT_QUEUE                 wait_queue_head_t
 
 /* sound mixer stuff */ 
-#include <linux/config.h>
 #if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
 # define REGISTER_MIXER 1
 #endif
@@ -678,7 +678,7 @@
 	struct CARRIER_DETECT *cd;
 	int                   count, max1,max2,val1,val2, val,this;
     
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	lock_kernel();
 #endif
     
@@ -691,7 +691,7 @@
 
 	msp->thread = current;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	unlock_kernel();
 #endif
 
@@ -933,7 +933,7 @@
 	struct msp3400c *msp = client->data;
 	int mode,val,i,std;
     
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	lock_kernel();
 #endif
     
@@ -946,7 +946,7 @@
 
 	msp->thread = current;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	unlock_kernel();
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
--- v2.3.99-pre5/linux/drivers/char/n_hdlc.c	Wed Dec 29 13:13:15 1999
+++ linux/drivers/char/n_hdlc.c	Fri Apr 21 13:17:03 2000
@@ -978,6 +978,8 @@
  * Return Value:
  * 
  * 	bit mask containing info on which ops will not block
+ *
+ * Note: Called without the kernel lock held. Which is fine.
  */
 static unsigned int n_hdlc_tty_poll (struct tty_struct *tty,
 	 struct file *filp, poll_table * wait)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- v2.3.99-pre5/linux/drivers/char/n_r3964.c	Tue Apr 11 15:09:16 2000
+++ linux/drivers/char/n_r3964.c	Fri Apr 21 13:19:08 2000
@@ -1429,6 +1429,7 @@
    TRACE_L("set_termios");
 }
 
+/* Called without the kernel lock held - fine */
 static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
 		      struct poll_table_struct *wait)
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.3.99-pre5/linux/drivers/char/n_tty.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/n_tty.c	Fri Apr 21 15:21:18 2000
@@ -226,10 +226,10 @@
 		nr = space;
 	if (nr > sizeof(buf))
 	    nr = sizeof(buf);
-	nr -= copy_from_user(buf, inbuf, nr);
-	if (!nr)
-		return 0;
-	
+
+	if (copy_from_user(buf, inbuf, nr))
+		return -EFAULT;
+
 	for (i = 0, cp = buf; i < nr; i++, cp++) {
 		switch (*cp) {
 		case '\n':
@@ -1166,6 +1166,7 @@
 	return (b - buf) ? b - buf : retval;
 }
 
+/* Called without the kernel lock held - fine */
 static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait)
 {
 	unsigned int mask = 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/nvram.c linux/drivers/char/nvram.c
--- v2.3.99-pre5/linux/drivers/char/nvram.c	Sun Feb 13 19:29:03 2000
+++ linux/drivers/char/nvram.c	Fri Apr 21 15:17:57 2000
@@ -372,7 +372,7 @@
 
     if (offset >= begin + len)
 		return( 0 );
-    *start = buffer + (begin - offset);
+    *start = buffer + (offset - begin);
     return( size < begin + len - offset ? size : begin + len - offset );
 	
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.3.99-pre5/linux/drivers/char/pc_keyb.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/char/pc_keyb.c	Fri Apr 21 13:12:24 2000
@@ -59,6 +59,9 @@
 
 static void kbd_write_command_w(int data);
 static void kbd_write_output_w(int data);
+#ifdef CONFIG_PSMOUSE
+static void aux_write_ack(int val);
+#endif
 
 spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
 static unsigned char handle_kbd_event(void);
@@ -76,6 +79,8 @@
 
 static int __init psaux_init(void);
 
+#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */
+ 
 static struct aux_queue *queue;	/* Mouse data buffer. */
 static int aux_count = 0;
 /* used when we send commands to the mouse that expect an ACK. */
@@ -396,6 +401,11 @@
 		}
 		mouse_reply_expected = 0;
 	}
+	else if(scancode == AUX_RECONNECT){
+		queue->head = queue->tail = 0;  /* Flush input queue */
+		aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */
+		return;
+	}
 
 	add_mouse_randomness(scancode);
 	if (aux_count) {
@@ -964,6 +974,7 @@
 	return retval;
 }
 
+/* No kernel lock held - fine */
 static unsigned int aux_poll(struct file *file, poll_table * wait)
 {
 	poll_wait(file, &queue->proc_list, wait);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/planb.c linux/drivers/char/planb.c
--- v2.3.99-pre5/linux/drivers/char/planb.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/planb.c	Wed Apr 12 09:38:53 2000
@@ -8,9 +8,7 @@
 
     Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
 
-    Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu)
-	(Some codes are stolen from proposed v4l2 videodev.c
-		of Bill Dirks <dirks@rendition.com>)
+    Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu)
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -94,11 +92,7 @@
 static unsigned char saa_status(int, struct planb *);
 static void saa_set(unsigned char, unsigned char, struct planb *);
 static void saa_init_regs(struct planb *);
-static void * rvmalloc(unsigned long);
-static void rvfree(void *, unsigned long);
-static unsigned long vmalloc_to_bus(void *);
-static unsigned long vmalloc_to_phys(void *);
-static int fbuffer_alloc(struct planb *);
+static int grabbuf_alloc(struct planb *);
 static int vgrab(struct planb *, struct video_mmap *);
 static void add_clip(struct planb *, struct video_clip *);
 static void fill_cmd_buff(struct planb *);
@@ -125,82 +119,36 @@
 /* Memory management functions */
 /*******************************/
 
-static void * rvmalloc(unsigned long size)
+static int grabbuf_alloc(struct planb *pb)
 {
-	void *mem, *memptr;
-	unsigned long page;
-        
-	mem=vmalloc(size);
-	if (mem) 
-	{
-		memset(mem, 0, size); /* Clear the ram out, leave no junk */
-		memptr = mem;
-		while (size > 0) 
-                {
-	                page = vmalloc_to_phys(memptr);
-			mem_map_reserve(MAP_NR(phys_to_virt(page)));
-			memptr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
-	return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-	void *memptr;
-        unsigned long page;
-        
-	if (mem) 
-	{
-		memptr = mem;
-		while (size > 0) 
-                {
-	                page = vmalloc_to_phys(memptr);
-			mem_map_unreserve(MAP_NR(phys_to_virt(page)));
-			memptr += PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-		vfree(mem);
-	}
-}
-
-/*  Useful for using vmalloc()ed memory as DMA target  */
-static unsigned long vmalloc_to_bus(void *virt)
-{
-	pgd_t		*pgd;
-	pmd_t		*pmd;
-	pte_t		*pte;
-	unsigned long	a = (unsigned long)virt;
-
-	if (pgd_none(*(pgd = pgd_offset(current->mm, a))) ||
-	    pmd_none(*(pmd = pmd_offset(pgd,         a))) ||
-	    pte_none(*(pte = pte_offset(pmd,         a))))
-		return 0;
-	return virt_to_bus((void *)pte_page(*pte))
-		+ (a & (PAGE_SIZE - 1));
-}
+	int i, npage;
 
-static unsigned long vmalloc_to_phys(void *virt) {
-	return virt_to_phys(bus_to_virt(vmalloc_to_bus(virt)));
-}
-
-/*
- *	Create the giant waste of buffer space we need for now
- *	until we get DMA to user space sorted out (probably 2.3.x)
- *
- *	We only create this as and when someone uses mmap
- */
- 
-static int fbuffer_alloc(struct planb *pb)
-{
-	if(!pb->fbuffer)
-		pb->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS
-					* PLANB_MAX_FBUF);
-	else
-		printk(KERN_ERR "PlanB: Double alloc of fbuffer!\n");
-	if(!pb->fbuffer)
+	npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1)
+#ifndef PLANB_GSCANLINE
+		+ MAX_LNUM
+#endif /* PLANB_GSCANLINE */
+		);
+	if ((pb->rawbuf = (unsigned char**) kmalloc (npage
+				* sizeof(unsigned long), GFP_KERNEL)) == 0)
+		return -ENOMEM;
+	for (i = 0; i < npage; i++) {
+		pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL
+								|GFP_DMA, 0);
+		if (!pb->rawbuf[i])
+			break;
+		set_bit(PG_reserved, &mem_map[MAP_NR(pb->rawbuf[i])].flags);
+	}
+	if (i-- < npage) {
+		printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n");
+		for (; i > 0; i--) {
+			clear_bit(PG_reserved,
+				&mem_map[MAP_NR(pb->rawbuf[i])].flags);
+			free_pages((unsigned long)pb->rawbuf[i], 0);
+		}
+		kfree(pb->rawbuf);
 		return -ENOBUFS;
+	}
+	pb->rawbuf_size = npage;
 	return 0;
 }
 
@@ -446,11 +394,8 @@
 						+ PLANB_DUMMY);
 	pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
 
-	pb->fbuffer = (unsigned char *)rvmalloc(MAX_GBUFFERS * PLANB_MAX_FBUF);
-	if (!pb->fbuffer) {
-		kfree(pb->priv_space);
-		return -ENOMEM;
-	}
+	pb->rawbuf = NULL;
+	pb->rawbuf_size = 0;
 	pb->grabbing = 0;
 	for (i = 0; i < MAX_GBUFFERS; i++) {
 		pb->frame_stat[i] = GBUFFER_UNUSED;
@@ -461,31 +406,23 @@
 #ifndef PLANB_GSCANLINE
 		pb->lsize[i] = 0;
 		pb->lnum[i] = 0;
-		pb->l_fr_addr[i]=(unsigned char *)rvmalloc(PAGE_SIZE*MAX_LNUM);
-		if (!pb->l_fr_addr[i]) {
-			int j;
-			kfree(pb->priv_space);
-			rvfree((void *)pb->fbuffer, MAX_GBUFFERS
-							* PLANB_MAX_FBUF);
-			for(j = 0; j < i; j++)
-				rvfree((void *)pb->l_fr_addr[j], PAGE_SIZE
-								* MAX_LNUM);
-			return -ENOMEM;
-		}
 #endif /* PLANB_GSCANLINE */
 	}
 	pb->gcount = 0;
 	pb->suspend = 0;
 	pb->last_fr = -999;
 	pb->prev_last_fr = -999;
-	return 0;   
+
+	/* Reset DMA controllers */
+	planb_dbdma_stop(&pb->planb_base->ch2);
+	planb_dbdma_stop(&pb->planb_base->ch1);
+
+	return 0;
 }
 
 static void planb_prepare_close(struct planb *pb)
 {
-#ifndef PLANB_GSCANLINE
 	int i;
-#endif
 
 	/* make sure the dma's are idle */
 	planb_dbdma_stop(&pb->planb_base->ch2);
@@ -496,16 +433,15 @@
 		pb->priv_space = 0;
 		pb->cmd_buff_inited = 0;
 	}
-	if(pb->fbuffer)
-		rvfree((void *)pb->fbuffer, MAX_GBUFFERS*PLANB_MAX_FBUF);
-	pb->fbuffer = NULL;
-#ifndef PLANB_GSCANLINE
-	for(i = 0; i < MAX_GBUFFERS; i++) {
-		if(pb->l_fr_addr[i])
-			rvfree((void *)pb->l_fr_addr[i], PAGE_SIZE * MAX_LNUM);
-		pb->l_fr_addr[i] = NULL;
+	if(pb->rawbuf) {
+		for (i = 0; i < pb->rawbuf_size; i++) {
+			clear_bit(PG_reserved,
+				&mem_map[MAP_NR(pb->rawbuf[i])].flags);
+			free_pages((unsigned long)pb->rawbuf[i], 0);
+		}
+		kfree(pb->rawbuf);
 	}
-#endif /* PLANB_GSCANLINE */
+	pb->rawbuf = NULL;
 }
 
 /*****************************/
@@ -940,12 +876,8 @@
        0,
        0,
 };
-#define PLANB_PALETTE_MAX 15
 
-#define SWAP4(x) (((x>>24) & 0x000000ff) |\
-                  ((x>>8)  & 0x0000ff00) |\
-                  ((x<<8)  & 0x00ff0000) |\
-                  ((x<<24) & 0xff000000))
+#define PLANB_PALETTE_MAX 15
 
 static inline int overlay_is_active(struct planb *pb)
 {
@@ -962,9 +894,10 @@
 	unsigned int fr = mp->frame;
 	unsigned int format;
 
-	if(pb->fbuffer==NULL) {
-		if(fbuffer_alloc(pb))
-			return -ENOBUFS;
+	if(pb->rawbuf==NULL) {
+		int err;
+		if((err=grabbuf_alloc(pb)))
+			return err;
 	}
 
 	IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
@@ -984,12 +917,10 @@
 		return -EINVAL;
 
 	planb_lock(pb);
-	pb->gbuffer[fr] = (unsigned char *)(pb->fbuffer + PLANB_MAX_FBUF * fr);
 	if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
 			format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
-#ifdef PLANB_GSCANLINE
 		int i;
-#else
+#ifndef PLANB_GSCANLINE
 		unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
 								* pb->gfmt[fr];
 		unsigned int nsize = mp->width * mp->height * format;
@@ -1001,10 +932,15 @@
 #ifndef PLANB_GSCANLINE
 		if(pb->gnorm_switch[fr])
 			nsize = 0;
-		if(nsize < osize)
-			memset((void *)(pb->gbuffer[fr] + nsize), 0,
-								osize - nsize);
-		memset((void *)pb->l_fr_addr[fr], 0, PAGE_SIZE * pb->lnum[fr]);
+		if (nsize < osize) {
+			for(i = pb->gbuf_idx[fr]; osize > 0; i++) {
+				memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
+				osize -= PAGE_SIZE;
+			}
+		}
+		for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr]
+							+ pb->lnum[fr]; i++)
+			memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
 #else
 /* XXX TODO */
 /*
@@ -1228,7 +1164,7 @@
 	unsigned long	base;
 #endif
 	unsigned long	jump;
-	unsigned char	*vaddr;
+	int		pagei;
 	volatile struct dbdma_cmd *c1;
 	volatile struct dbdma_cmd *jump_addr;
 
@@ -1277,11 +1213,12 @@
 
 	/* even field data: */
 
-	vaddr = pb->gbuffer[fr];
+	pagei = pb->gbuf_idx[fr];
 #ifdef PLANB_GSCANLINE
 	for (i = 0; i < nlines; i += stepsize) {
 		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
-				vmalloc_to_bus(vaddr + i * scanline), jump);
+					virt_to_bus(pb->rawbuf[pagei
+					+ i * scanline / PAGE_SIZE]), jump);
 	}
 #else
 	i = 0;
@@ -1289,7 +1226,7 @@
 	do {
 	    int j;
 
-	    base = vmalloc_to_bus((void*)vaddr);
+	    base = virt_to_bus(pb->rawbuf[pagei]);
 	    nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
 	    for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
 		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
@@ -1304,11 +1241,13 @@
 			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
 				+ count * nlpp * stepsize + leftover1, jump);
 		    } else {
-			pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count * nlpp
-							* stepsize + leftover1;
+			pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
+					+ count * nlpp * stepsize + leftover1;
+			pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
+			pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0;
 			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
-				vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE
-							* pb->lnum[fr]), jump);
+				virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
+						+ pb->lnum[fr]]), jump);
 			if(++pb->lnum[fr] > MAX_LNUM)
 				pb->lnum[fr]--;
 		    }
@@ -1316,7 +1255,7 @@
 		    i += stepsize;
 		}
 	    }
-	    vaddr += PAGE_SIZE;
+	    pagei++;
 	} while(i < nlines);
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
 	c1 = jump_addr;
@@ -1341,18 +1280,19 @@
 #ifdef PLANB_GSCANLINE
 	for (i = 1; i < nlines; i += stepsize) {
 		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
-				vmalloc_to_bus(vaddr + i * scanline), jump);
+					virt_to_bus(pb->rawbuf[pagei
+					+ i * scanline / PAGE_SIZE]), jump);
 	}
 #else
 	i = 1;
 	leftover1 = 0;
-	vaddr = pb->gbuffer[fr];
+	pagei = pb->gbuf_idx[fr];
 	if(nlines <= 1)
 	    goto skip;
 	do {
 	    int j;
 
-	    base = vmalloc_to_bus((void*)vaddr);
+	    base = virt_to_bus(pb->rawbuf[pagei]);
 	    nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
 	    if(leftover1 >= count) {
 		tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
@@ -1369,11 +1309,14 @@
 		    leftover1 = 0;
 		else {
 		    if(lov0 > count) {
-			pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count
-					* (nlpp * stepsize + 1) + leftover1;
+			pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
+				+ count * (nlpp * stepsize + 1) + leftover1;
+			pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
+			pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize
+									- lov0;
 			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
-				vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE
-							* pb->lnum[fr]), jump);
+				virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
+							+ pb->lnum[fr]]), jump);
 			if(++pb->lnum[fr] > MAX_LNUM)
 				pb->lnum[fr]--;
 			i += stepsize;
@@ -1381,7 +1324,7 @@
 		    leftover1 = count * stepsize - lov0;
 		}
 	    }
-	    vaddr += PAGE_SIZE;
+	    pagei++;
 	} while(i < nlines);
 skip:
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
@@ -1390,7 +1333,7 @@
 
 cmd_tab_data_end:
 	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
-			(fr << 2) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
+			(fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
 	/* stop it */
 	tab_cmd_dbdma(c1, DBDMA_STOP, 0);
 
@@ -1406,13 +1349,15 @@
 	IDEBUG("PlanB: planb_irq()\n");
 
 	/* get/clear interrupt status bits */
+	eieio();
 	stat = in_le32(&pb->planb_base->intr_stat);
 	astat = stat & pb->intr_mask;
-	out_le32(&pb->planb_base->intr_stat, PLANB_IRQ_CMD_MASK
+	out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ
 					& ~astat & stat & ~PLANB_GEN_IRQ);
+	IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat);
 
 	if(astat & PLANB_FRM_IRQ) {
-		unsigned int fr = stat >> 2;
+		unsigned int fr = stat >> 9;
 #ifndef PLANB_GSCANLINE
 		int i;
 #endif
@@ -1425,9 +1370,16 @@
 #ifndef PLANB_GSCANLINE
 		IDEBUG("PlanB: %d * %d bytes are being copied over\n",
 				pb->lnum[fr], pb->lsize[fr]);
-		for(i = 0; i < pb->lnum[fr]; i++)
-			memcpy(pb->l_to_addr[fr][i], pb->l_fr_addr[fr]
-					+ PAGE_SIZE * i, pb->lsize[fr]);
+		for(i = 0; i < pb->lnum[fr]; i++) {
+			int first = pb->lsize[fr] - pb->l_to_next_size[fr][i];
+
+			memcpy(pb->l_to_addr[fr][i],
+				pb->rawbuf[pb->l_fr_addr_idx[fr] + i],
+				first);
+			memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]],
+				pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first,
+						pb->l_to_next_size[fr][i]);
+		}
 #endif
 		pb->frame_stat[fr] = GBUFFER_DONE;
 		pb->grabbing--;
@@ -1848,6 +1800,8 @@
 				IDEBUG("PlanB: waiting for grab"
 							" done (%d)\n", i);
  			        interruptible_sleep_on(&pb->capq);
+				if(signal_pending(current))
+					return -EINTR;
 				goto chk_grab;
                         case GBUFFER_DONE:
                                 pb->frame_stat[i] = GBUFFER_UNUSED;
@@ -2058,38 +2012,27 @@
 	return 0;
 }
 
-/*
- *	This maps the vmalloced and reserved fbuffer to user space.
- *
- *  FIXME: 
- *  - PAGE_READONLY should suffice!?
- *  - remap_page_range is kind of inefficient for page by page remapping.
- *    But e.g. pte_alloc() does not work in modules ... :-(
- */
- 
 static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size)
 {
-	struct planb *pb=(struct planb *)dev;
-        unsigned long start=(unsigned long) adr;
-	unsigned long page;
-	void *pos;
+	int i;
+	struct planb *pb = (struct planb *)dev;
+        unsigned long start = (unsigned long)adr;
 
-	if (size>MAX_GBUFFERS*PLANB_MAX_FBUF)
+	if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
 	        return -EINVAL;
-	if (!pb->fbuffer)
-	{
-		if(fbuffer_alloc(pb))
-			return -EINVAL;
-	}
-	pos = (void *)pb->fbuffer;
-	while (size > 0) 
-	{
-	        page = vmalloc_to_phys(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
-		        return -EAGAIN;
-		start+=PAGE_SIZE;
-		pos+=PAGE_SIZE;
-		size-=PAGE_SIZE;    
+	if (!pb->rawbuf) {
+		int err;
+		if((err=grabbuf_alloc(pb)))
+			return err;
+	}
+	for (i = 0; i < pb->rawbuf_size; i++) {
+		if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]),
+						PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		if (size <= PAGE_SIZE)
+			break;
+		size -= PAGE_SIZE;
 	}
 	return 0;
 }
@@ -2125,6 +2068,7 @@
 {
 	unsigned char saa_rev;
 	int i, result;
+	unsigned long flags;
 
 	memset ((void *) &pb->win, 0, sizeof (struct planb_window));
 	/* Simple sanity check */
@@ -2167,7 +2111,7 @@
 	pb->tab_size = PLANB_MAXLINES + 40;
 	pb->suspend = 0;
 	pb->lock = 0;
-	pb->lockq = NULL;
+	init_waitqueue_head(&pb->lockq);
 	pb->ch1_cmd = 0;
 	pb->ch2_cmd = 0;
 	pb->mask = 0;
@@ -2175,7 +2119,7 @@
 	pb->offset = 0;
 	pb->user = 0;
 	pb->overlay = 0;
-	pb->suspendq = NULL;
+	init_waitqueue_head(&pb->suspendq);
 	pb->cmd_buff_inited = 0;
 	pb->frame_buffer_phys = 0;
 
@@ -2191,19 +2135,20 @@
 	/* clear interrupt mask */
 	pb->intr_mask = PLANB_CLR_IRQ;
 
+	save_flags(flags); cli();
         result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
-        if (result==-EINVAL) {
-                printk(KERN_ERR "PlanB: Bad irq number (%d) or handler\n",
-                       (int)pb->irq);
-                return result;
-        }
-	if (result==-EBUSY) {
-                printk(KERN_ERR "PlanB: I don't know why, but IRQ %d busy\n",
-			(int)pb->irq);
-                return result;
-        }
-        if (result < 0) 
-                return result;
+        if (result < 0) {
+	        if (result==-EINVAL)
+	                printk(KERN_ERR "PlanB: Bad irq number (%d) "
+						"or handler\n", (int)pb->irq);
+		else if (result==-EBUSY)
+			printk(KERN_ERR "PlanB: I don't know why, "
+					"but IRQ %d is busy\n", (int)pb->irq);
+		restore_flags(flags);
+		return result;
+	}
+	disable_irq(pb->irq);
+	restore_flags(flags);
         
 	/* Now add the template and register the device unit. */
 	memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
@@ -2216,26 +2161,27 @@
 	pb->picture.depth = pb->win.depth;
 
 	pb->frame_stat=NULL;
-	pb->capq=NULL;
+	init_waitqueue_head(&pb->capq);
 	for(i=0; i<MAX_GBUFFERS; i++) {
-		pb->gbuffer[i]=NULL;
+		pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE;
 		pb->gwidth[i]=0;
 		pb->gheight[i]=0;
 		pb->gfmt[i]=0;
 		pb->cap_cmd[i]=NULL;
 #ifndef PLANB_GSCANLINE
-		pb->l_fr_addr[i]=NULL;
+		pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF
+						/ PAGE_SIZE + 1) + MAX_LNUM * i;
 		pb->lsize[i] = 0;
 		pb->lnum[i] = 0;
 #endif
 	}
-	pb->fbuffer=NULL;
+	pb->rawbuf=NULL;
 	pb->grabbing=0;
 
-	/* clear interrupts */
+	/* enable interrupts */
 	out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
-	/* set interrupt mask */
 	pb->intr_mask = PLANB_FRM_IRQ;
+	enable_irq(pb->irq);
 
 	if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0)
 		return -1;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/planb.h linux/drivers/char/planb.h
--- v2.3.99-pre5/linux/drivers/char/planb.h	Sat May 15 15:05:36 1999
+++ linux/drivers/char/planb.h	Wed Apr 12 09:38:53 2000
@@ -8,7 +8,7 @@
 
     Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
 
-    Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu)
+    Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu)
 
 
     This program is free software; you can redistribute it and/or modify
@@ -69,6 +69,7 @@
 
 /* for capture operations */
 #define MAX_GBUFFERS	2
+/* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */
 #ifdef PLANB_GSCANLINE
 #define PLANB_MAX_FBUF	0x240000	/* 576 * 1024 * 4 */
 #define TAB_FACTOR	(1)
@@ -132,8 +133,7 @@
 	volatile unsigned int		intr_stat;	/* 0x104: irq status */
 #define PLANB_CLR_IRQ		0x00		/* clear Plan B interrupt */
 #define PLANB_GEN_IRQ		0x01		/* assert Plan B interrupt */
-#define PLANB_FRM_IRQ		0x02		/* end of frame */
-#define PLANB_IRQ_CMD_MASK	0x00000003U	/* reserve 2 lsbs for command */
+#define PLANB_FRM_IRQ		0x0100		/* end of frame */
 	unsigned int			pad3[1];	/* empty? */
 	volatile unsigned int		reg5;		/* 0x10c: ??? */
 	unsigned int			pad4[60];	/* empty? */
@@ -199,8 +199,9 @@
 	wait_queue_head_t capq;
 	int last_fr;
 	int prev_last_fr;
-        unsigned char *fbuffer;
-	unsigned char *gbuffer[MAX_GBUFFERS];
+	unsigned char **rawbuf;
+	int rawbuf_size;
+	int gbuf_idx[MAX_GBUFFERS];
 	volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS];
 	volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS];
 	volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS];
@@ -218,8 +219,10 @@
 #else
 #define MAX_LNUM 431	/* change this if PLANB_MAXLINES or */
 			/* PLANB_MAXPIXELS changes */
-	unsigned char *l_fr_addr[MAX_GBUFFERS];
+	int l_fr_addr_idx[MAX_GBUFFERS];
 	unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM];
+	int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM];
+	int l_to_next_size[MAX_GBUFFERS][MAX_LNUM];
 	int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS];
 #endif
 };
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.99-pre5/linux/drivers/char/ppdev.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/char/ppdev.c	Wed Apr 26 09:29:15 2000
@@ -569,15 +569,16 @@
 	return 0;
 }
 
+/* No kernel lock held - fine */
 static unsigned int pp_poll (struct file * file, poll_table * wait)
 {
 	struct pp_struct *pp = file->private_data;
 	unsigned int mask = 0;
 
+	poll_wait (file, &pp->irq_wait, wait);
 	if (atomic_read (&pp->irqc))
 		mask |= POLLIN | POLLRDNORM;
 
-	poll_wait (file, &pp->irq_wait, wait);
 	return mask;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.3.99-pre5/linux/drivers/char/pty.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/char/pty.c	Tue Apr 25 16:53:13 2000
@@ -138,7 +138,7 @@
 		       const unsigned char *buf, int count)
 {
 	struct tty_struct *to = tty->link;
-	int	c=0, n;
+	int	c=0, n, room;
 	char	*temp_buffer;
 
 	if (!to || tty->stopped)
@@ -149,7 +149,9 @@
 		temp_buffer = &tty->flip.char_buf[0];
 		while (count > 0) {
 			/* check space so we don't copy needlessly */ 
-			n = MIN(count, to->ldisc.receive_room(to));
+			n = to->ldisc.receive_room(to);
+			if (n > count)
+				n = count;
 			if (!n) break;
 
 			n  = MIN(n, PTY_BUF_SIZE);
@@ -161,7 +163,9 @@
 			}
 
 			/* check again in case the buffer filled up */
-			n = MIN(n, to->ldisc.receive_room(to));
+			room = to->ldisc.receive_room(to);
+			if (n > room)
+				n = room;
 			if (!n) break;
 			buf   += n; 
 			c     += n;
@@ -356,7 +360,11 @@
 	memset(&pty_driver, 0, sizeof(struct tty_driver));
 	pty_driver.magic = TTY_DRIVER_MAGIC;
 	pty_driver.driver_name = "pty_master";
+#ifdef CONFIG_DEVFS_FS
 	pty_driver.name = "pty/m%d";
+#else
+	pty_driver.name = "pty";
+#endif
 	pty_driver.major = PTY_MASTER_MAJOR;
 	pty_driver.minor_start = 0;
 	pty_driver.num = NR_PTYS;
@@ -387,7 +395,11 @@
 	pty_slave_driver = pty_driver;
 	pty_slave_driver.driver_name = "pty_slave";
 	pty_slave_driver.proc_entry = 0;
+#ifdef CONFIG_DEVFS_FS
 	pty_slave_driver.name = "pty/s%d";
+#else
+	pty_slave_driver.name = "ttyp";
+#endif
 	pty_slave_driver.subtype = PTY_TYPE_SLAVE;
 	pty_slave_driver.major = PTY_SLAVE_MAJOR;
 	pty_slave_driver.minor_start = 0;
@@ -440,7 +452,11 @@
 			init_waitqueue_head(&ptm_state[i][j].open_wait);
 		
 		pts_driver[i] = pty_slave_driver;
+#ifdef CONFIG_DEVFS_FS
 		pts_driver[i].name = "pts/%d";
+#else
+		pts_driver[i].name = "pts";
+#endif
 		pts_driver[i].proc_entry = 0;
 		pts_driver[i].major = UNIX98_PTY_SLAVE_MAJOR+i;
 		pts_driver[i].minor_start = 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.3.99-pre5/linux/drivers/char/random.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/random.c	Wed Apr 12 09:38:52 2000
@@ -763,7 +763,12 @@
 
 void add_keyboard_randomness(unsigned char scancode)
 {
-	add_timer_randomness(&keyboard_timer_state, scancode);
+	static unsigned char last_scancode = 0;
+	/* ignore autorepeat (multiple key down w/o key up) */
+	if (scancode != last_scancode) {
+		last_scancode = scancode;
+		add_timer_randomness(&keyboard_timer_state, scancode);
+	}
 }
 
 void add_mouse_randomness(__u32 mouse_data)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.3.99-pre5/linux/drivers/char/rtc.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/char/rtc.c	Fri Apr 21 13:19:51 2000
@@ -550,6 +550,7 @@
 }
 
 #ifndef __alpha__
+/* Called without the kernel lock - fine */
 static unsigned int rtc_poll(struct file *file, poll_table *wait)
 {
 	unsigned long l, flags;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.99-pre5/linux/drivers/char/serial.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/char/serial.c	Wed Apr 26 09:11:31 2000
@@ -3159,7 +3159,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -4164,7 +4164,7 @@
 		PCI_ANY_ID, PCI_ANY_ID,
 		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
 		0, 0, pci_siig20x_fn },
-	/* Computone devices submitted by Doug McNash dmcnash@computone.com */
+	/* Computone devices submitted by Doug McNash dougm@computone.com */
 	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
 		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
 		SPCI_FL_BASE0, 4, 921600, /* IOMEM */
@@ -4477,7 +4477,7 @@
 #if (LINUX_VERSION_CODE > 0x20100)
 	serial_driver.driver_name = "serial";
 #endif
-#if (LINUX_VERSION_CODE > 0x2032D)
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
 	serial_driver.name = "tts/%d";
 #else
 	serial_driver.name = "ttyS";
@@ -4525,7 +4525,7 @@
 	 * major number and the subtype code.
 	 */
 	callout_driver = serial_driver;
-#if (LINUX_VERSION_CODE > 0x2032D)
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
 	callout_driver.name = "cua/%d";
 #else
 	callout_driver.name = "cua";
@@ -4683,7 +4683,7 @@
  *
  *	The port specified is deconfigured and its resources are freed. Any
  *	user of the port is disconnected as if carrier was dropped. Line is
- *	the port number returned by register_serial.
+ *	the port number returned by register_serial().
  */
 
 void unregister_serial(int line)
@@ -5023,6 +5023,6 @@
 
 /*
   Local variables:
-  compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce  -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
+  compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce  -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
   End:
 */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- v2.3.99-pre5/linux/drivers/char/sh-sci.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/char/sh-sci.c	Mon Apr 24 13:54:17 2000
@@ -1,4 +1,4 @@
-/* $Id: sh-sci.c,v 1.36 2000/03/22 13:32:10 gniibe Exp $
+/* $Id: sh-sci.c,v 1.40 2000/04/15 06:57:29 gniibe Exp $
  *
  *  linux/drivers/char/sh-sci.c
  *
@@ -191,14 +191,13 @@
 #if defined(CONFIG_SH_SCIF_SERIAL)
 	if (C_CRTSCTS(port->gs.tty))
 		fcr_val |= 0x08;
+	else
+		ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */
 	ctrl_out(fcr_val, SCFCR);
 #endif
 
 	sci_set_baud(port);
 	ctrl_out(SCSCR_INIT, SCSCR);	/* TIE=0,RIE=0,TE=1,RE=1 */
-#if 0 /* defined(CONFIG_SH_SCIF_SERIAL) */
-	ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */
-#endif
 	sci_enable_rx_interrupts(port);
 }
 
@@ -661,7 +660,7 @@
 	sci_driver.subtype = SERIAL_TYPE_NORMAL;
 	sci_driver.init_termios = tty_std_termios;
 	sci_driver.init_termios.c_cflag =
-		B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+		B115200 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS;
 	sci_driver.flags = TTY_DRIVER_REAL_RAW;
 	sci_driver.refcount = &sci_refcount;
 	sci_driver.table = sci_table;
@@ -716,12 +715,6 @@
 	return 0;
 }
 
-#ifdef MODULE
-#define sci_init init_module
-#else
-#define sci_init rs_init
-#endif
-
 int __init sci_init(void)
 {
 	struct sci_port *port;
@@ -756,6 +749,8 @@
 #endif
 	return 0;		/* Return -EIO when not detected */
 }
+
+module_init(sci_init);
 
 #ifdef MODULE
 #undef func_enter
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/sx.c linux/drivers/char/sx.c
--- v2.3.99-pre5/linux/drivers/char/sx.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/char/sx.c	Thu Apr 13 17:06:05 2000
@@ -33,7 +33,12 @@
  *
  * Revision history:
  * $Log: sx.c,v $
- * Revision 1.32  2000/03/07 90:00:00  wolff,pvdl
+ * Revision 1.33  2000/03/09 10:00:00  pvdl,wolff
+ * - Fixed module and port counting
+ * - Fixed signal handling
+ * - Fixed an Ooops
+ * 
+ * Revision 1.32  2000/03/07 09:00:00  wolff,pvdl
  * - Fixed some sx_dprintk typos
  * - added detection for an invalid board/module configuration
  *
@@ -195,8 +200,8 @@
  * */
 
 
-#define RCS_ID "$Id: sx.c,v 1.32 2000/03/07 17:01:02 wolff, pvdl Exp $"
-#define RCS_REV "$Revision: 1.32 $"
+#define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $"
+#define RCS_REV "$Revision: 1.33 $"
 
 
 #include <linux/module.h>
@@ -231,8 +236,9 @@
 
 #include "sxboards.h"
 #include "sxwindow.h"
-#include <linux/generic_serial.h>
+
 #include <linux/compatmac.h>
+#include <linux/generic_serial.h>
 #include "sx.h"
 
 
@@ -241,11 +247,11 @@
    if you want more than 4 boards.  */
 
 
-
 /* Why the hell am I defining these here? */
 #define SX_TYPE_NORMAL 1
 #define SX_TYPE_CALLOUT 2
 
+
 #ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
 #define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
 #endif
@@ -767,6 +773,7 @@
 	if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS);
 	sx_write_channel_byte (port, hi_op, t);
 	sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
+
 	func_exit ();
 }
 
@@ -882,6 +889,9 @@
 
 	func_enter2();
 
+	if (!port->gs.tty)
+		return 0;
+
 	/* What is this doing here? -- REW
 	   Ha! figured it out. It is to allow you to get DTR active again
 	   if you've dropped it with stty 0. Moved to set_baud, where it
@@ -1043,7 +1053,7 @@
 		sx_disable_tx_interrupts (port);
 	}
 
-	if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+	if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
 		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 		    port->gs.tty->ldisc.write_wakeup)
 			(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
@@ -1294,6 +1304,8 @@
 
 	sx_interrupt (0, board, NULL);
 
+	init_timer(&board->timer);
+
 	board->timer.expires = jiffies + sx_poll;
 	add_timer (&board->timer);
 	func_exit ();
@@ -1389,7 +1401,7 @@
 	func_enter();
 
 	port->gs.flags &= ~ GS_ACTIVE;
-	if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
+	if (port->gs.tty && (port->gs.tty->termios->c_cflag & HUPCL)) {
 		sx_setsignals (port, 0, 0);
 		sx_reconfigure_port(port);
 	}
@@ -1452,6 +1464,8 @@
 
 	tty->driver_data = port;
 	port->gs.tty = tty;
+	if (!port->gs.count)
+		MOD_INC_USE_COUNT;
 	port->gs.count++;
 
 	sx_dprintk (SX_DEBUG_OPEN, "starting port\n");
@@ -1463,19 +1477,13 @@
 	sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n");
 	if (retval) {
 		port->gs.count--;
+		if (port->gs.count) MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
 	port->gs.flags |= GS_ACTIVE;
 	sx_setsignals (port, 1,1);
 
-	sx_dprintk (SX_DEBUG_OPEN, "before inc_use_count (count=%d.\n", 
-	            port->gs.count);
-	if (port->gs.count == 1) {
-		MOD_INC_USE_COUNT;
-	}
-	sx_dprintk (SX_DEBUG_OPEN, "after inc_use_count\n");
-
 #if 0
 	if (sx_debug & SX_DEBUG_OPEN)
 		my_hd ((unsigned char *)port, sizeof (*port));
@@ -1487,8 +1495,8 @@
 
 	if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
 		printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
-		MOD_DEC_USE_COUNT;
 		port->gs.count--;
+		if (!port->gs.count) MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -1497,8 +1505,10 @@
 	            retval, port->gs.count);
 
 	if (retval) {
-		MOD_DEC_USE_COUNT;
-		port->gs.count--;
+		/* 
+		 * Don't lower gs.count here because sx_close() will be called later
+		 */ 
+
 		return retval;
 	}
 	/* tty->low_latency = 1; */
@@ -1530,7 +1540,21 @@
    exit minicom.  I expect an "oops".  -- REW */
 static void sx_hungup (void *ptr)
 {
+	struct sx_port *port = ptr; 
 	func_enter ();
+
+	sx_setsignals (port, 0, 0);
+	sx_reconfigure_port(port);	
+	sx_send_command (port, HS_CLOSE, 0, 0);
+
+	if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) {
+		if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) {
+			printk (KERN_ERR 
+			        "sx: sent the force_close command, but card didn't react\n");
+		} else
+			sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n");
+	}
+
 	MOD_DEC_USE_COUNT;
 	func_exit ();
 }
@@ -1543,6 +1567,9 @@
 	int to = 5 * HZ; 
 
 	func_enter ();
+
+	sx_setsignals (port, 0, 0);
+	sx_reconfigure_port(port);	
 	sx_send_command (port, HS_CLOSE, 0, 0);
 
 	while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) {
@@ -1562,6 +1589,11 @@
 
 	sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", 
 	            5 * HZ - to - 1, port->gs.count);
+
+	if(port->gs.count) {
+		sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count);
+		port->gs.count = 0;
+	}
 
 	MOD_DEC_USE_COUNT;
 	func_exit ();
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.3.99-pre5/linux/drivers/char/synclink.c	Wed Dec 29 13:13:15 1999
+++ linux/drivers/char/synclink.c	Fri Apr 21 15:17:57 2000
@@ -3901,7 +3901,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 	
 }	/* end of mgsl_read_proc() */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.99-pre5/linux/drivers/char/tty_io.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/char/tty_io.c	Fri Apr 21 16:11:05 2000
@@ -367,6 +367,7 @@
 	return -EIO;
 }
 
+/* No kernel lock held - none needed ;) */
 static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait)
 {
 	return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
@@ -1410,6 +1411,7 @@
 	return 0;
 }
 
+/* No kernel lock held - fine */
 static unsigned int tty_poll(struct file * filp, poll_table * wait)
 {
 	struct tty_struct * tty;
@@ -2015,6 +2017,8 @@
 			mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
 			break;
 		default:
+			if (driver->major == PTY_MASTER_MAJOR)
+				flags |= DEVFS_FL_AUTO_OWNER;
 			break;
 	}
 	if ( (minor <  driver->minor_start) || 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/videodev.c linux/drivers/char/videodev.c
--- v2.3.99-pre5/linux/drivers/char/videodev.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/char/videodev.c	Thu Apr 13 07:54:32 2000
@@ -221,26 +221,26 @@
 
 /**
  *	video_register_device - register video4linux devices
- *	@vfd: Video device structure we want to register
+ *	@vfd: video device structure we want to register
  *	@type: type of device to register
  *	FIXME: needs a semaphore on 2.3.x
  *	
  *	The registration code assigns minor numbers based on the type
  *	requested. -ENFILE is returned in all the device slots for this
- *	catetory are full. If not then the minor field is set and the
- *	driver initialize function is called (if non NULL).
+ *	category are full. If not then the minor field is set and the
+ *	driver initialize function is called (if non %NULL).
  *
  *	Zero is returned on success.
  *
  *	Valid types are
  *
- *	VFL_TYPE_GRABBER - A frame grabber
+ *	%VFL_TYPE_GRABBER - A frame grabber
  *
- *	VFL_TYPE_VTX - A teletext device
+ *	%VFL_TYPE_VTX - A teletext device
  *
- *	VFL_TYPE_VBI - Vertical blank data (undecoded)
+ *	%VFL_TYPE_VBI - Vertical blank data (undecoded)
  *
- *	VFL_TYPE_RADIO - A radio card	
+ *	%VFL_TYPE_RADIO - A radio card	
  */
  
 int video_register_device(struct video_device *vfd, int type)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/Config.in linux/drivers/i2o/Config.in
--- v2.3.99-pre5/linux/drivers/i2o/Config.in	Fri Oct 22 13:21:49 1999
+++ linux/drivers/i2o/Config.in	Wed Apr 12 09:38:53 2000
@@ -3,7 +3,9 @@
 
 tristate 'I2O support' CONFIG_I2O
 
-dep_tristate '  I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
+if [ "$CONFIG_PCI" = "y" ]; then
+   dep_tristate '  I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
+fi
 dep_tristate '  I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O
 if [ "$CONFIG_NET" = "y" ]; then
    dep_tristate '  I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/README linux/drivers/i2o/README
--- v2.3.99-pre5/linux/drivers/i2o/README	Thu Nov 11 20:11:34 1999
+++ linux/drivers/i2o/README	Wed Apr 12 09:38:53 2000
@@ -16,6 +16,7 @@
 	Debugging SCSI and Block OSM
 
 Deepak Saxena, Intel Corp.
+	Various core/block extensions
 	/proc interface, bug fixes
 	Ioctl interfaces for control
 	Debugging LAN OSM
@@ -64,24 +65,22 @@
 STATUS:
 
 o	The core setup works within limits.
-o	The scsi layer seems to almost work. I'm still chasing down the hang
-	bug.
-o	The block OSM is fairly minimal but does seem to work.
+o	The scsi layer seems to almost work. 
+           I'm still chasing down the hang bug.
+o	The block OSM is mostly functional
 o	LAN OSM works with FDDI and Ethernet cards.
 
 TO DO:
 
 General:
-o	Support multiple IOP's and tell them about each other
 o	Provide hidden address space if asked
 o	Long term message flow control
 o	PCI IOP's without interrupts are not supported yet
 o	Push FAIL handling into the core
 o	DDM control interfaces for module load etc
-o	Event handling
+o       Add I2O 2.0 support (Deffered to 2.5 kernel)
 
 Block:
-o	Real error handler
 o	Multiple major numbers
 o	Read ahead and cache handling stuff. Talk to Ingo and people
 o	Power management
@@ -90,9 +89,11 @@
 SCSI:
 o	Find the right way to associate drives/luns/busses
 
-Lan:	Batch mode sends
-	Performance tuning
-	Event handling
+Lan:	
+o	Performance tuning
+o	Test Fibre Channel code
+o	Fix lan_set_mc_list()
 
 Tape:
 o	Anyone seen anything implementing this ?
+           (D.S: Will attempt to do so if spare cycles permit)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/README.ioctl linux/drivers/i2o/README.ioctl
--- v2.3.99-pre5/linux/drivers/i2o/README.ioctl	Thu Nov 11 20:11:34 1999
+++ linux/drivers/i2o/README.ioctl	Wed Apr 12 09:38:53 2000
@@ -20,7 +20,7 @@
 
 This document and the I2O user space interface are currently maintained
 by Deepak Saxena.  Please send all comments, errata, and bug fixes to
-deepak@plexity.net
+deepak@csociety.purdue.edu
 
 II. IOP Access
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.3.99-pre5/linux/drivers/i2o/i2o_block.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/i2o/i2o_block.c	Wed Apr 12 09:38:53 2000
@@ -1,30 +1,35 @@
 /*
- *	I2O block device driver. 
+ * I2O Random Block Storage Class OSM
  *
- *	(C) Copyright 1999   Red Hat Software
+ * (C) Copyright 1999 Red Hat Software
  *	
- *	Written by Alan Cox, Building Number Three Ltd
+ * Written by Alan Cox, Building Number Three Ltd
  *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- * 	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
+ * This program is 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 is a beta test release. Most of the good code was taken
- *	from the nbd driver by Pavel Machek, who in turn took some of it
- *	from loop.c. Isn't free software great for reusability 8)
+ * This is a beta test release. Most of the good code was taken
+ * from the nbd driver by Pavel Machek, who in turn took some of it
+ * from loop.c. Isn't free software great for reusability 8)
+ *
+ * Fixes/additions:
+ *	Steve Ralston:	
+ *		Multiple device handling error fixes,
+ *		Added a queue depth.
+ *	Alan Cox:	
+ *		FC920 has an rmw bug. Dont or in the end marker.
+ *		Removed queue walk, fixed for 64bitness.
+ *	Deepak Saxena:
+ *		Independent queues per IOP
+ *		Support for dynamic device creation/deletion
+ *		Code cleanup	
+ *    Support for larger I/Os through merge* functions 
+ *       (taken from DAC960 driver)
  *
- *	Fixes:
- *		Steve Ralston:	Multiple device handling error fixes,
- *				Added a queue depth.
- *		Alan Cox:	FC920 has an rmw bug. Dont or in the
- *				end marker.
- *				Removed queue walk, fixed for 64bitness.
  *	To do:
- *		Multiple majors
  *		Serial number scanning to find duplicates for FC multipathing
- *		Set the new max_sectors according to max message size
- *		Use scatter gather chains for bigger I/O sizes
  */
 
 #include <linux/major.h>
@@ -47,8 +52,11 @@
 #include <linux/reboot.h>
 
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
 
 #define MAJOR_NR I2O_MAJOR
 
@@ -56,9 +64,44 @@
 
 #define MAX_I2OB	16
 
-#define MAX_I2OB_DEPTH	32                
+#define MAX_I2OB_DEPTH	128
 #define MAX_I2OB_RETRIES 4
 
+//#define DRIVERDEBUG
+#ifdef DRIVERDEBUG
+#define DEBUG( s )
+#else
+#define DEBUG( s ) printk( s ) 
+#endif
+
+/*
+ * Events that this OSM is interested in
+ */
+#define I2OB_EVENT_MASK	I2O_EVT_IND_BSA_VOLUME_LOAD |	\
+				I2O_EVT_IND_BSA_VOLUME_UNLOAD | \
+				I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \
+				I2O_EVT_IND_BSA_CAPACITY_CHANGE
+
+
+/*
+ * I2O Block Error Codes - should be in a header file really...
+ */
+#define I2O_BSA_DSC_SUCCESS             0x0000
+#define I2O_BSA_DSC_MEDIA_ERROR         0x0001
+#define I2O_BSA_DSC_ACCESS_ERROR        0x0002
+#define I2O_BSA_DSC_DEVICE_FAILURE      0x0003
+#define I2O_BSA_DSC_DEVICE_NOT_READY    0x0004
+#define I2O_BSA_DSC_MEDIA_NOT_PRESENT   0x0005
+#define I2O_BSA_DSC_MEDIA_LOCKED        0x0006
+#define I2O_BSA_DSC_MEDIA_FAILURE       0x0007
+#define I2O_BSA_DSC_PROTOCOL_FAILURE    0x0008
+#define I2O_BSA_DSC_BUS_FAILURE         0x0009
+#define I2O_BSA_DSC_ACCESS_VIOLATION    0x000A
+#define I2O_BSA_DSC_WRITE_PROTECTED     0x000B
+#define I2O_BSA_DSC_DEVICE_RESET        0x000C
+#define I2O_BSA_DSC_VOLUME_CHANGED      0x000D
+#define I2O_BSA_DSC_TIMEOUT             0x000E
+
 /*
  *	Some of these can be made smaller later
  */
@@ -71,14 +114,20 @@
 
 static int i2ob_context;
 
+/*
+ * I2O Block device descriptor 
+ */
 struct i2ob_device
 {
 	struct i2o_controller *controller;
 	struct i2o_device *i2odev;
+	int unit;
 	int tid;
 	int flags;
 	int refcnt;
 	struct request *head, *tail;
+	request_queue_t *req_queue;
+	int max_segments;
 	int done_flag;
 };
 
@@ -87,53 +136,81 @@
  *	We should cache align these to avoid ping-ponging lines on SMP
  *	boxes under heavy I/O load...
  */
- 
 struct i2ob_request
 {
 	struct i2ob_request *next;
 	struct request *req;
 	int num;
-};
+} __cacheline_aligned;
 
+/*
+ * Per IOP requst queue information
+ *
+ * We have a separate requeust_queue_t per IOP so that a heavilly
+ * loaded I2O block device on an IOP does not starve block devices
+ * across all I2O controllers.
+ * 
+ */
+struct i2ob_iop_queue
+{
+	atomic_t queue_depth;
+	struct i2ob_request request_queue[MAX_I2OB_DEPTH];
+	struct i2ob_request *i2ob_qhead;
+	request_queue_t req_queue;
+};
+static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS] = {NULL};
 
 /*
  *	Each I2O disk is one of these.
  */
 
 static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
-static int i2ob_devices = 0;
+static int i2ob_dev_count = 0;
 static struct hd_struct i2ob[MAX_I2OB<<4];
 static struct gendisk i2ob_gendisk;	/* Declared later */
 
-static atomic_t queue_depth;		/* For flow control later on */
-static struct i2ob_request i2ob_queue[MAX_I2OB_DEPTH+1];
-static struct i2ob_request *i2ob_qhead;
+/*
+ * Mutex and spin lock for event handling synchronization
+ * evt_msg contains the last event.
+ */
+DECLARE_MUTEX(i2ob_evt_sem);
+static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int evt_msg[MSG_FRAME_SIZE>>2];
+DECLARE_WAIT_QUEUE_HEAD(i2ob_evt_wait);
 
 static struct timer_list i2ob_timer;
 static int i2ob_timer_started = 0;
 
-#define DEBUG( s )
-/* #define DEBUG( s ) printk( s ) 
- */
-
+static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *,
+	 struct i2o_message *);
+static void i2ob_new_device(struct i2o_controller *, struct i2o_device *);
+static void i2ob_del_device(struct i2o_controller *, struct i2o_device *);
+static void i2ob_reboot_event(void);
 static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
 static void i2ob_end_request(struct request *);
-static void i2ob_request(request_queue_t * q);
+static void i2ob_request(request_queue_t *);
+static int i2ob_init_iop(unsigned int);
+static request_queue_t* i2ob_get_queue(kdev_t);
+static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);
+static int do_i2ob_revalidate(kdev_t, int);
+static int i2ob_evt(void *);
+
+static int evt_pid = 0;
+static int evt_running = 0;
 
 /*
- * Dump messages.
+ * I2O OSM registration structure...keeps getting bigger and bigger :)
  */
-static void i2ob_dump_msg(struct i2ob_device *dev,u32 *msg,int size)
+static struct i2o_handler i2o_block_handler =
 {
-        int cnt;
-
-        printk(KERN_INFO "\n\ni2o message:\n");
-        for (cnt = 0; cnt<size; cnt++)
-        {
-                printk(KERN_INFO "m[%d]=%x\n",cnt,msg[cnt]);
-        }
-        printk(KERN_INFO "\n");
-}
+	i2o_block_reply,
+	i2ob_new_device,
+	i2ob_del_device,
+	i2ob_reboot_event,
+	"I2O Block OSM",
+	0,
+	I2O_CLASS_RANDOM_BLOCK_STORAGE
+};
 
 /*
  *	Get a message
@@ -159,12 +236,15 @@
 	struct request *req = ireq->req;
 	struct buffer_head *bh = req->bh;
 	int count = req->nr_sectors<<9;
+	char *last = NULL;
+	unsigned short size = 0;
 
+	// printk(KERN_INFO "i2ob_send called\n");
 	/* Map the message to a virtual address */
 	msg = c->mem_offset + m;
 	
 	/*
-         * Build the message based on the request.
+	 * Build the message based on the request.
 	 */
 	__raw_writel(i2ob_context|(unit<<8), msg+8);
 	__raw_writel(ireq->num, msg+12);
@@ -184,18 +264,26 @@
 		__raw_writel(1<<16, msg+16);
 		while(bh!=NULL)
 		{
-			/*
-			 *	Its best to do this in one not or it in
-			 *	later. mptr is in PCI space so fast to write
-			 *	sucky to read.
-			 */
-			if(bh->b_reqnext)
-				__raw_writel(0x10000000|(bh->b_size), mptr);
+			if(bh->b_data == last) {
+				size += bh->b_size;
+				last += bh->b_size;
+				if(bh->b_reqnext)
+					__raw_writel(0x14000000|(size), mptr-8);
+				else
+					__raw_writel(0xD4000000|(size), mptr-8);
+			}
 			else
-				__raw_writel(0xD0000000|(bh->b_size), mptr);
-	
-			__raw_writel(virt_to_bus(bh->b_data), mptr+4);
-			mptr+=8;
+			{
+				if(bh->b_reqnext)
+					__raw_writel(0x10000000|(bh->b_size), mptr);
+				else
+					__raw_writel(0xD0000000|(bh->b_size), mptr);
+				__raw_writel(virt_to_bus(bh->b_data), mptr+4);
+				mptr += 8;	
+				size = bh->b_size;
+				last = bh->b_data + size;
+			}
+
 			count -= bh->b_size;
 			bh = bh->b_reqnext;
 		}
@@ -203,22 +291,41 @@
 	else if(req->cmd == WRITE)
 	{
 		__raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4);
-		__raw_writel(1<<16, msg+16);
+		/* 
+		 * Allow replies to come back once data is cached in the controller
+		 * This allows us to handle writes quickly thus giving more of the
+		 * queue to reads.
+		 */
+		__raw_writel(0x00000010, msg+16);
 		while(bh!=NULL)
 		{
-			if(bh->b_reqnext)
-				__raw_writel(0x14000000|(bh->b_size), mptr);
+			if(bh->b_data == last) {
+				size += bh->b_size;
+				last += bh->b_size;
+				if(bh->b_reqnext)
+					__raw_writel(0x14000000|(size), mptr-8);
+				else
+					__raw_writel(0xD4000000|(size), mptr-8);
+			}
 			else
-				__raw_writel(0xD4000000|(bh->b_size), mptr);
+			{
+				if(bh->b_reqnext)
+					__raw_writel(0x14000000|(bh->b_size), mptr);
+				else
+					__raw_writel(0xD4000000|(bh->b_size), mptr);
+				__raw_writel(virt_to_bus(bh->b_data), mptr+4);
+				mptr += 8;	
+				size = bh->b_size;
+				last = bh->b_data + size;
+			}
+
 			count -= bh->b_size;
-			__raw_writel(virt_to_bus(bh->b_data), mptr+4);
-			mptr+=8;
 			bh = bh->b_reqnext;
 		}
 	}
 	__raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
 	
-	if(req->current_nr_sectors > 8)
+	if(req->current_nr_sectors > i2ob_max_sectors[unit])
 		printk("Gathered sectors %ld.\n", 
 			req->current_nr_sectors);
 			
@@ -228,7 +335,7 @@
 	}
 
 	i2o_post_message(c,m);
-	atomic_inc(&queue_depth);
+	atomic_inc(&i2ob_queues[c->unit]->queue_depth);
 
 	return 0;
 }
@@ -239,17 +346,18 @@
  *	must hold the lock.
  */
  
-static inline void i2ob_unhook_request(struct i2ob_request *ireq)
+static inline void i2ob_unhook_request(struct i2ob_request *ireq, 
+	unsigned int iop)
 {
-	ireq->next = i2ob_qhead;
-	i2ob_qhead = ireq;
+	ireq->next = i2ob_queues[iop]->i2ob_qhead;
+	i2ob_queues[iop]->i2ob_qhead = ireq;
 }
 
 /*
  *	Request completion handler
  */
  
-static void i2ob_end_request(struct request *req)
+static inline void i2ob_end_request(struct request *req)
 {
 	/*
 	 * Loop until all of the buffers that are linked
@@ -257,19 +365,74 @@
 	 * unlocked.
 	 */
 
-//	printk("ending request %p: ", req);
-	while (end_that_request_first( req, !req->errors, "i2o block" ))
-	{
-//		printk(" +\n");
-	}
+	while (end_that_request_first( req, !req->errors, "i2o block" ));
 
 	/*
 	 * It is now ok to complete the request.
 	 */
-	
-//	printk("finishing ");
 	end_that_request_last( req );
-//	printk("done\n");
+}
+
+/*
+ * Request merging functions
+ */
+static inline int i2ob_new_segment(request_queue_t *q, struct request *req,
+				  int __max_segments)
+{
+	int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments;
+
+	if (__max_segments < max_segments)
+		max_segments = __max_segments;
+
+	if (req->nr_segments < max_segments) {
+		req->nr_segments++;
+		q->elevator.nr_segments++;
+		return 1;
+	}
+	return 0;
+}
+
+static int i2ob_back_merge(request_queue_t *q, struct request *req, 
+			     struct buffer_head *bh, int __max_segments)
+{
+	if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+		return 1;
+	return i2ob_new_segment(q, req, __max_segments);
+}
+
+static int i2ob_front_merge(request_queue_t *q, struct request *req, 
+			      struct buffer_head *bh, int __max_segments)
+{
+	if (bh->b_data + bh->b_size == req->bh->b_data)
+		return 1;
+	return i2ob_new_segment(q, req, __max_segments);
+}
+
+static int i2ob_merge_requests(request_queue_t *q,
+				struct request *req,
+				struct request *next,
+				int __max_segments)
+{
+	int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments;
+	int total_segments = req->nr_segments + next->nr_segments;
+	int same_segment;
+
+	if (__max_segments < max_segments)
+		max_segments = __max_segments;
+
+	same_segment = 0;
+	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+	{
+		total_segments--;
+		same_segment = 1;
+	}
+    
+	if (total_segments > max_segments)
+		return 0;
+
+	q->elevator.nr_segments -= same_segment;
+	req->nr_segments = total_segments;
+	return 1;
 }
 
 
@@ -280,136 +443,253 @@
 static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
 {
 	unsigned long flags;
-	struct i2ob_request *ireq;
+	struct i2ob_request *ireq = NULL;
 	u8 st;
 	u32 *m = (u32 *)msg;
 	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
-	
+	struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)];
+
+	/*
+	 * FAILed message
+	 */
 	if(m[0] & (1<<13))
 	{
-		printk("IOP fail.\n");
-		printk("From %d To %d Cmd %d.\n",
-			(m[1]>>12)&0xFFF,
-			m[1]&0xFFF,
-			m[1]>>24);
-		printk("Failure Code %d.\n", m[4]>>24);
-		if(m[4]&(1<<16))
-			printk("Format error.\n");
-		if(m[4]&(1<<17))
-			printk("Path error.\n");
-		if(m[4]&(1<<18))
-			printk("Path State.\n");
-		if(m[4]&(1<<18))
-			printk("Congestion.\n");
-		
-		m=(u32 *)bus_to_virt(m[7]);
-		printk("Failing message is %p.\n", m);
-		
-		/* We need to up the request failure count here and maybe
-		   abort it */
-		ireq=&i2ob_queue[m[3]];
+		/*
+		 * FAILed message from controller
+		 * We increment the error count and abort it
+		 *
+		 * In theory this will never happen.  The I2O block class
+		 * speficiation states that block devices never return
+		 * FAILs but instead use the REQ status field...but
+		 * better be on the safe side since no one really follows
+		 * the spec to the book :)
+		 */
+		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
+		ireq->req->errors++;
+
+		spin_lock_irqsave(&io_request_lock, flags);
+		i2ob_unhook_request(ireq, c->unit);
+		i2ob_end_request(ireq->req);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	
 		/* Now flush the message by making it a NOP */
 		m[0]&=0x00FFFFFF;
 		m[0]|=(I2O_CMD_UTIL_NOP)<<24;
 		i2o_post_message(c,virt_to_bus(m));
-		
+
+		return;
 	}
-	else
+
+	if(msg->function == I2O_CMD_UTIL_EVT_REGISTER)
+	{
+		spin_lock(&i2ob_evt_lock);
+		memcpy(&evt_msg, m, msg->size);
+		spin_unlock(&i2ob_evt_lock);
+		wake_up_interruptible(&i2ob_evt_wait);
+		return;
+	}
+
+	if(!dev->i2odev)
 	{
-		if(m[2]&0x40000000)
-		{
-			int * ptr = (int *)m[3];
-			if(m[4]>>24)
-				*ptr = -1;
-			else
-				*ptr = 1;
-			return;
-		}
 		/*
-		 *	Lets see what is cooking. We stuffed the
-		 *	request in the context.
+		 * This is HACK, but Intel Integrated RAID allows user
+		 * to delete a volume that is claimed, locked, and in use 
+		 * by the OS. We have to check for a reply from a
+		 * non-existent device and flag it as an error or the system 
+		 * goes kaput...
 		 */
+		ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
+		ireq->req->errors++;
+		printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n");
+		spin_lock_irqsave(&io_request_lock, flags);
+		i2ob_unhook_request(ireq, c->unit);
+		i2ob_end_request(ireq->req);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}	
+
+	/*
+	 *	Lets see what is cooking. We stuffed the
+	 *	request in the context.
+	 */
 		 
-		ireq=&i2ob_queue[m[3]];
-		st=m[4]>>24;
-	
-		if(st!=0)
-		{
-			printk(KERN_ERR "i2ob: error %08X\n", m[4]);
-			ireq->req->errors++;	
-			if (ireq->req->errors < MAX_I2OB_RETRIES)
-			{
-				u32 retry_msg;
-				struct i2ob_device *dev;
+	ireq=&i2ob_queues[c->unit]->request_queue[m[3]];
+	st=m[4]>>24;
 
-  				printk(KERN_ERR "i2ob: attempting retry %d for request %p\n",ireq->req->errors+1,ireq->req);
-     				
-		                /* 
-				 * Get a message for this retry.
-				 */
-				dev = &i2ob_dev[(unit&0xF0)];
-                		retry_msg = i2ob_get(dev);
+	if(st!=0)
+	{
+		char *bsa_errors[] = 
+		{ 
+			"Success", 
+			"Media Error", 
+			"Failure communicating to device",
+			"Device Failure",
+			"Device is not ready",
+			"Media not present",
+			"Media is locked by another user",
+			"Media has failed",
+			"Failure communicating to device",
+			"Device bus failure",
+			"Device is locked by another user",
+			"Device is write protected",
+			"Device has reset",
+			"Volume has changed, waiting for acknowledgement"
+		};
+				
+		printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, 
+			bsa_errors[m[4]&0XFFFF]);
+		if(m[4]&0x00FF0000)
+			printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF );
+		printk("\n");
 
-                		/* 
-				 * If we cannot get a message then
-				 * forget the retry and fail the
-				 * request.   Note that since this is
-				 * being called from the interrupt 
-				 * handler, a request has just been 
-				 * completed and there will most likely 
-				 * be space on the inbound message
-				 * fifo so this won't happen often.
-				 */
-                		if(retry_msg!=0xFFFFFFFF)
-				{
-			                /*
-			                 * Decrement the queue depth since
-			                 * this request has completed and
-			                 * it will be incremented again when
-			                 * i2ob_send is called below.
-			                 */
-			                atomic_dec(&queue_depth);
-
-			                /*
-			                 * Send the request again.
-			                 */
-			                i2ob_send(retry_msg, dev,ireq,i2ob[unit].start_sect, (unit&0xF0));
-					/*
-					 * Don't fall through.
-					 */
-					return;
-				}
-			}		
-		}
-		else
-			ireq->req->errors = 0;
+		ireq->req->errors++;	
 	}
-		
+	else
+		ireq->req->errors = 0;
+
 	/*
 	 *	Dequeue the request. We use irqsave locks as one day we
 	 *	may be running polled controllers from a BH...
 	 */
 	
 	spin_lock_irqsave(&io_request_lock, flags);
-	i2ob_unhook_request(ireq);
+	i2ob_unhook_request(ireq, c->unit);
 	i2ob_end_request(ireq->req);
-	
+	atomic_dec(&i2ob_queues[c->unit]->queue_depth);
+
 	/*
 	 *	We may be able to do more I/O
 	 */
-	 
-	atomic_dec(&queue_depth);
-	i2ob_request(NULL);
+	i2ob_request(dev->req_queue);
+
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
-static struct i2o_handler i2o_block_handler =
+/* 
+ * Event handler.  Needs to be a separate thread b/c we may have
+ * to do things like scan a partition table, or query parameters
+ * which cannot be done from an interrupt or from a bottom half.
+ */
+static int i2ob_evt(void *dummy)
 {
-	i2o_block_reply,
-	"I2O Block OSM",
-	0,
-	I2O_CLASS_RANDOM_BLOCK_STORAGE
-};
+	unsigned int evt;
+	unsigned int flags;
+	int unit;
+	int i;
+
+	lock_kernel();
+	exit_files(current);
+	daemonize();
+	unlock_kernel();
+
+	strcpy(current->comm, "i2oblock");
+	evt_running = 1;
+
+	while(1)
+	{
+		interruptible_sleep_on(&i2ob_evt_wait);
+ 		if(signal_pending(current)) {
+			evt_running = 0;
+			return 0;
+		}
+
+		printk(KERN_INFO "Doing something in i2o_block event thread\n");
+		
+		/*
+		 * Keep another CPU/interrupt from overwriting the 
+		 * message while we're reading it
+		 *
+		 * We stuffed the unit in the TxContext and grab the event mask
+		 * None of the BSA we care about events have EventData
+		 */
+		spin_lock_irqsave(&i2ob_evt_lock, flags);
+		unit = evt_msg[3];
+		evt = evt_msg[4];
+		spin_unlock_irqrestore(&i2ob_evt_lock, flags);
+
+		switch(evt)
+		{
+			/*
+			 * New volume loaded on same TID, so we just re-install.
+			 * The TID/controller don't change as it is the same
+			 * I2O device.  It's just new media that we have to
+			 * rescan.
+			 */
+			case I2O_EVT_IND_BSA_VOLUME_LOAD:
+			{
+				i2ob_install_device(i2ob_dev[unit].i2odev->controller, 
+					i2ob_dev[unit].i2odev, unit);
+				break;
+			}
+
+			/*
+			 * No media, so set all parameters to 0 and set the media
+			 * change flag. The I2O device is still valid, just doesn't
+			 * have media, so we don't want to clear the controller or
+			 * device pointer.
+			 */
+			case I2O_EVT_IND_BSA_VOLUME_UNLOAD:
+			{
+				for(i = unit; i <= unit+15; i++)
+				{
+					i2ob_sizes[i] = 0;
+					i2ob_hardsizes[i] = 0;
+					i2ob_max_sectors[i] = 0;
+					i2ob[i].nr_sects = 0;
+					i2ob_gendisk.part[i].nr_sects = 0;
+				}
+				i2ob_media_change_flag[unit] = 1;
+				break;
+			}
+
+			case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ:
+				printk(KERN_WARNING "%s: Attempt to eject locked media\n", 
+					i2ob_dev[unit].i2odev->dev_name);
+				break;
+
+			/*
+			 * The capacity has changed and we are going to be
+			 * updating the max_sectors and other information 
+			 * about this disk.  We try a revalidate first. If
+			 * the block device is in use, we don't want to
+			 * do that as there may be I/Os bound for the disk
+			 * at the moment.  In that case we read the size 
+			 * from the device and update the information ourselves
+			 * and the user can later force a partition table
+			 * update through an ioctl.
+			 */
+			case I2O_EVT_IND_BSA_CAPACITY_CHANGE:
+			{
+				u64 size;
+
+				if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY)
+					continue;
+
+	  			if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 )
+					i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8);
+
+				spin_lock_irqsave(&io_request_lock, flags);	
+				i2ob_sizes[unit] = (int)(size>>10);
+				i2ob_gendisk.part[unit].nr_sects = size>>9;
+				i2ob[unit].nr_sects = (int)(size>>9);
+				spin_unlock_irqrestore(&io_request_lock, flags);	
+				break;
+			}
+
+			/*
+			 * An event we didn't ask for.  Call the card manufacturer
+			 * and tell them to fix their firmware :)
+			 */
+			default:
+				printk(KERN_INFO "%s: Received event we didn't register for\n"
+					KERN_INFO "   Call I2O card manufacturer\n", 
+					i2ob_dev[unit].i2odev->dev_name);
+				break;
+		}
+	};
+
+	return 0;
+}
 
 /*
  * The timer handler will attempt to restart requests 
@@ -418,7 +698,7 @@
  * had no more room in its inbound fifo.  
  */
 
-static void i2ob_timer_handler(unsigned long dummy)
+static void i2ob_timer_handler(unsigned long q)
 {
 	unsigned long flags;
 
@@ -437,7 +717,7 @@
 	/* 
 	 * Restart any requests.
 	 */
-	i2ob_request(NULL);
+	i2ob_request((request_queue_t*)q);
 
 	/* 
 	 * Free the lock.
@@ -452,8 +732,7 @@
  *	on us. We must unlink CURRENT in this routine before we return, if
  *	we use it.
  */
-
-static void i2ob_request(request_queue_t * q)
+static void i2ob_request(request_queue_t *q)
 {
 	struct request *req;
 	struct i2ob_request *ireq;
@@ -461,26 +740,30 @@
 	struct i2ob_device *dev;
 	u32 m;
 
-	while (!QUEUE_EMPTY) {
+	// printk(KERN_INFO "i2ob_request() called with queue %p\n", q);
+
+	while (!list_empty(&q->queue_head)) {
 		/*
 		 *	On an IRQ completion if there is an inactive
 		 *	request on the queue head it means it isnt yet
 		 *	ready to dispatch.
 		 */
-		if(CURRENT->rq_status == RQ_INACTIVE)
+		req = blkdev_entry_next_request(&q->queue_head);
+
+		if(req->rq_status == RQ_INACTIVE)
 			return;
 			
-		/*
-		 *	Queue depths probably belong with some kind of
-		 *	generic IOP commit control. Certainly its not right
-		 *	its global!
+		unit = MINOR(req->rq_dev);
+		dev = &i2ob_dev[(unit&0xF0)];
+
+		/* 
+		 *	Queue depths probably belong with some kind of 
+		 *	generic IOP commit control. Certainly its not right 
+		 *	its global!  
 		 */
-		if(atomic_read(&queue_depth)>=MAX_I2OB_DEPTH)
+		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth)>=MAX_I2OB_DEPTH)
 			break;
 
-		req = CURRENT;
-		unit = MINOR(req->rq_dev);
-		dev = &i2ob_dev[(unit&0xF0)];
 		/* Get a message */
 		m = i2ob_get(dev);
 
@@ -506,6 +789,7 @@
 				 * 500ms.
 				 */
 				i2ob_timer.expires = jiffies + (HZ >> 1);
+				i2ob_timer.data = (unsigned int)q;
 
 				/*
 				 * Start it.
@@ -514,68 +798,79 @@
 				add_timer(&i2ob_timer);
 			}
 		}
+
+		/*
+		 * Everything ok, so pull from kernel queue onto our queue
+		 */
 		req->errors = 0;
-		blkdev_dequeue_request(req);
+		blkdev_dequeue_request(req);	
 		req->sem = NULL;
-		
-		ireq = i2ob_qhead;
-		i2ob_qhead = ireq->next;
+
+		ireq = i2ob_queues[dev->unit]->i2ob_qhead;
+		i2ob_queues[dev->unit]->i2ob_qhead = ireq->next;
 		ireq->req = req;
 
 		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0));
 	}
 }
 
+
 /*
  *	SCSI-CAM for ioctl geometry mapping
  *	Duplicated with SCSI - this should be moved into somewhere common
  *	perhaps genhd ?
+ *
+ * LBA -> CHS mapping table taken from:
+ *
+ * "Incorporating the I2O Architecture into BIOS for Intel Architecture 
+ *  Platforms" 
+ *
+ * This is an I2O document that is only available to I2O members,
+ * not developers.
+ *
+ * From my understanding, this is how all the I2O cards do this
+ *
+ * Disk Size      | Sectors | Heads | Cylinders
+ * ---------------+---------+-------+-------------------
+ * 1 < X <= 528M  | 63      | 16    | X/(63 * 16 * 512)
+ * 528M < X <= 1G | 63      | 32    | X/(63 * 32 * 512)
+ * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
+ * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
+ *
  */
- 
+#define	BLOCK_SIZE_528M		1081344
+#define	BLOCK_SIZE_1G		2097152
+#define	BLOCK_SIZE_21G		4403200
+#define	BLOCK_SIZE_42G		8806400
+#define	BLOCK_SIZE_84G		17612800
+
 static void i2o_block_biosparam(
 	unsigned long capacity,
 	unsigned short *cyls,
 	unsigned char *hds,
 	unsigned char *secs) 
 { 
-	unsigned long heads, sectors, cylinders, temp; 
+	unsigned long heads, sectors, cylinders; 
 
-	cylinders = 1024L;			/* Set number of cylinders to max */ 
-	sectors = 62L;      			/* Maximize sectors per track */ 
-
-	temp = cylinders * sectors;		/* Compute divisor for heads */ 
-	heads = capacity / temp;		/* Compute value for number of heads */
-	if (capacity % temp) {			/* If no remainder, done! */ 
-    		heads++;                	/* Else, increment number of heads */ 
-    		temp = cylinders * heads;	/* Compute divisor for sectors */ 
-    		sectors = capacity / temp;	/* Compute value for sectors per
-						       track */ 
-	    	if (capacity % temp) {		/* If no remainder, done! */ 
-			sectors++;                  /* Else, increment number of sectors */ 
-	      		temp = heads * sectors;	/* Compute divisor for cylinders */
-	      		cylinders = capacity / temp;/* Compute number of cylinders */ 
-		} 
-	} 
-	/* if something went wrong, then apparently we have to return
-	   a geometry with more than 1024 cylinders */
-	if (cylinders == 0 || heads > 255 || sectors > 63 || cylinders >1023) 
-	{
-		unsigned long temp_cyl;
-		
+	sectors = 63L;      			/* Maximize sectors per track */ 
+	if(capacity <= BLOCK_SIZE_528M)
+		heads = 16;
+	else if(capacity <= BLOCK_SIZE_1G)
+		heads = 32;
+	else if(capacity <= BLOCK_SIZE_21G)
 		heads = 64;
-		sectors = 32;
-		temp_cyl = capacity / (heads * sectors);
-		if (temp_cyl > 1024) 
-		{
-			heads = 255;
-			sectors = 63;
-		}
-		cylinders = capacity / (heads * sectors);
-	}
-	*cyls = (unsigned int) cylinders;	/* Stuff return values */ 
-	*secs = (unsigned int) sectors; 
-	*hds  = (unsigned int) heads; 
-} 
+	else if(capacity <= BLOCK_SIZE_42G)
+		heads = 128;
+	else
+		heads = 255;
+
+	cylinders = capacity / (heads * sectors);
+
+	*cyls = (unsigned short) cylinders;	/* Stuff return values */ 
+	*secs = (unsigned char) sectors; 
+	*hds  = (unsigned char) heads; 
+}
+
 
 /*
  *	Rescan the partition tables
@@ -587,7 +882,7 @@
 	int i;
 	
 	minor&=0xF0;
-	
+
 	i2ob_dev[minor].refcnt++;
 	if(i2ob_dev[minor].refcnt>maxu+1)
 	{
@@ -685,6 +980,21 @@
 	if (minor >= (MAX_I2OB<<4))
 		return -ENODEV;
 	dev = &i2ob_dev[(minor&0xF0)];
+
+	/*
+	 * This is to deail with the case of an application
+	 * opening a device and then the device dissapears while
+	 * it's in use, and then the application tries to release
+	 * it.  ex: Unmounting a deleted RAID volume at reboot. 
+	 * If we send messages, it will just cause FAILs since
+	 * the TID no longer exists.
+	 */
+	if(!dev->i2odev)
+		return 0;
+
+	/* Sync the device so we don't get errors */
+	fsync_dev(inode->i_rdev);
+
 	if (dev->refcnt <= 0)
 		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
 	dev->refcnt--;
@@ -701,6 +1011,7 @@
 		msg[3] = (u32)query_done;
 		msg[4] = 60<<16;
 		i2o_post_wait(dev->controller, msg, 20, 2);
+
 		/*
 		 *	Unlock the media
 		 */
@@ -714,7 +1025,7 @@
 		/*
  		 * Now unclaim the device.
 		 */
-		if (i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0)
+		if (i2o_release_device(dev->i2odev, &i2o_block_handler))
 			printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
 
 	}
@@ -737,22 +1048,21 @@
 	if (minor >= MAX_I2OB<<4)
 		return -ENODEV;
 	dev=&i2ob_dev[(minor&0xF0)];
-	if(dev->i2odev == NULL)
+
+	if(!dev->i2odev)	
 		return -ENODEV;
-		
+	
 	if(dev->refcnt++==0)
 	{ 
 		u32 msg[6];
-		int *query_done;
-		
 		
-		if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0)
+		if(i2o_claim_device(dev->i2odev, &i2o_block_handler))
 		{
 			dev->refcnt--;
+			printk(KERN_INFO "I2O Block: Could not open device\n");
 			return -EBUSY;
 		}
 		
-		query_done = &dev->done_flag;
 		/*
 		 *	Mount the media if needed. Note that we don't use
 		 *	the lock bit. Since we have to issue a lock if it
@@ -761,18 +1071,15 @@
 		 */
 		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;		
 		msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid;
-		msg[2] = i2ob_context|0x40000000;
-		msg[3] = (u32)query_done;
 		msg[4] = -1;
 		msg[5] = 0;
 		i2o_post_wait(dev->controller, msg, 24, 2);
+
 		/*
 		 *	Lock the media
 		 */
 		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
 		msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid;
-		msg[2] = i2ob_context|0x40000000;
-		msg[3] = (u32)query_done;
 		msg[4] = -1;
 		i2o_post_wait(dev->controller, msg, 20, 2);
 	}		
@@ -807,10 +1114,15 @@
 	int i;
 
 	/*
+	 * For logging purposes...
+	 */
+	printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", 
+			d->lct_data.tid, unit);	
+
+	/*
 	 *	Ask for the current media data. If that isn't supported
 	 *	then we ask for the device capacity data
 	 */
-	 
 	if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0
 	  || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 )
 	{
@@ -822,23 +1134,35 @@
 	i2ob_query_device(dev, 0x0000, 6, &status, 4);
 	i2ob_sizes[unit] = (int)(size>>10);
 	i2ob_hardsizes[unit] = blocksize;
+	i2ob_gendisk.part[unit].nr_sects = size>>9;
+	i2ob[unit].nr_sects = (int)(size>>9);
 
-	limit=4096;	/* 8 deep scatter gather */
+	/* Set limit based on inbound frame size */
+	limit = (d->controller->status_block->inbound_frame_size - 8)/2;
+	limit = limit<<9;
 
-	printk("Byte limit is %d.\n", limit);
+	/*
+	 * Max number of Scatter-Gather Elements
+	 */	
+	i2ob_dev[unit].max_segments = 
+		(d->controller->status_block->inbound_frame_size - 8)/2;
+
+	printk(KERN_INFO "Max Segments set to %d\n", 
+				i2ob_dev[unit].max_segments);
+	printk(KERN_INFO "Byte limit is %d.\n", limit);
 	
 	for(i=unit;i<=unit+15;i++)
-		i2ob_max_sectors[i]=(limit>>9);
-	
-	i2ob[unit].nr_sects = (int)(size>>9);
+	{
+		i2ob_max_sectors[i]=MAX_SECTORS;
+		i2ob_dev[i].max_segments = 
+			(d->controller->status_block->inbound_frame_size - 8)/2;
+	}
 
 	i2ob_query_device(dev, 0x0000, 0, &type, 1);
 	
 	sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4));
 
-	printk("%s: ", d->dev_name);
-	if(status&(1<<10))
-		printk("RAID ");
+	printk(KERN_INFO "%s: ", d->dev_name);
 	switch(type)
 	{
 		case 0: printk("Disk Storage");break;
@@ -848,13 +1172,15 @@
 		default:
 			printk("Type %d", type);
 	}
+	if(status&(1<<10))
+		printk("(RAID)");
 	if(((flags & (1<<3)) && !(status & (1<<3))) ||
 	   ((flags & (1<<4)) && !(status & (1<<4))))
 	{
-		printk(" Not loaded.\n");
-		return 0;
+		printk(KERN_INFO " Not loaded.\n");
+		return 1;
 	}
-	printk(" %dMb, %d byte sectors",
+	printk("- %dMb, %d byte sectors",
 		(int)(size>>20), blocksize);
 	if(status&(1<<0))
 	{
@@ -867,12 +1193,91 @@
 			printk(", %dKb cache", cachesize);
 	}
 	printk(".\n");
-	printk("%s: Maximum sectors/read set to %d.\n", 
+	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
 		d->dev_name, i2ob_max_sectors[unit]);
+
+	/* 
+	 * If this is the first I2O block device found on this IOP,
+	 * we need to initialize all the queue data structures
+	 * before any I/O can be performed. If it fails, this
+	 * device is useless.
+	 */
+	if(!i2ob_queues[c->unit]) {
+		if(i2ob_init_iop(c->unit))
+			return 1;
+	}
+
+	/* 
+	 * This will save one level of lookup/indirection in critical 
+	 * code so that we can directly get the queue ptr from the
+	 * device instead of having to go the IOP data structure.
+	 */
+	dev->req_queue = &i2ob_queues[c->unit]->req_queue;
+
 	grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9));
+
+	/*
+	 * Register for the events we're interested in and that the
+	 * device actually supports.
+	 */
+	i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, 
+		(I2OB_EVENT_MASK & d->lct_data.event_capabilities));
+
+	return 0;
+}
+
+/*
+ * Initialize IOP specific queue structures.  This is called
+ * once for each IOP that has a block device sitting behind it.
+ */
+static int i2ob_init_iop(unsigned int unit)
+{
+	int i;
+
+	i2ob_queues[unit] = (struct i2ob_iop_queue*)
+		kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC);
+	if(!i2ob_queues[unit])
+	{
+		printk(KERN_WARNING
+			"Could not allocate request queue for I2O block device!\n");
+		return -1;
+	}
+
+	for(i = 0; i< MAX_I2OB_DEPTH; i++)
+	{
+		i2ob_queues[unit]->request_queue[i].next = 
+			&i2ob_queues[unit]->request_queue[i+1];
+		i2ob_queues[unit]->request_queue[i].num = i;
+	}
+	
+	/* Queue is MAX_I2OB + 1... */
+	i2ob_queues[unit]->request_queue[i].next = NULL;
+	i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0];
+	atomic_set(&i2ob_queues[unit]->queue_depth, 0);
+
+	blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request);
+	blk_queue_headactive(&i2ob_queues[unit]->req_queue, 0);
+	i2ob_queues[unit]->req_queue.back_merge_fn = i2ob_back_merge;
+	i2ob_queues[unit]->req_queue.front_merge_fn = i2ob_front_merge;
+	i2ob_queues[unit]->req_queue.merge_requests_fn = i2ob_merge_requests;
+	i2ob_queues[unit]->req_queue.queuedata = &i2ob_queues[unit];
+
 	return 0;
 }
 
+/*
+ * Get the request queue for the given device.
+ */	
+static request_queue_t* i2ob_get_queue(kdev_t dev)
+{
+	int unit = MINOR(dev)&0xF0;
+
+	return i2ob_dev[unit].req_queue;
+}
+
+/*
+ * Probe the I2O subsytem for block class devices
+ */
 static void i2ob_probe(void)
 {
 	int i;
@@ -889,12 +1294,20 @@
 
 		for(d=c->devices;d!=NULL;d=d->next)
 		{
-			if(d->lct_data->class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE)
+			if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE)
 				continue;
 
-			if(d->lct_data->user_tid != 0xFFF)
+			if(d->lct_data.user_tid != 0xFFF)
 				continue;
 
+			if(i2o_claim_device(d, &i2o_block_handler))
+			{
+				printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit,
+					d->lct_data.tid);
+				printk(KERN_WARNING "\tDevice refused claim! Skipping installation\n");
+				continue;
+			}
+
 			if(unit<MAX_I2OB<<4)
 			{
  				/*
@@ -904,45 +1317,189 @@
 				struct i2ob_device *dev=&i2ob_dev[unit];
 				dev->i2odev = d; 
 				dev->controller = c;
-				dev->tid = d->lct_data->tid;
- 
-				/*
-				 * Insure the device can be claimed
-				 * before installing it.
-				 */
-				if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY )==0)
+				dev->unit = c->unit;
+				dev->tid = d->lct_data.tid;
+
+				if(i2ob_install_device(c,d,unit))
+					printk(KERN_WARNING "Could not install I2O block device\n");
+				else
 				{
-					printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit);
-					i2ob_install_device(c,d,unit);
-                                        unit+=16;
- 
-					/*
-					 * Now that the device has been
-					 * installed, unclaim it so that
-					 * it can be claimed by either
-					 * the block or scsi driver.
-					 */
-					if(i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY))
-						printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid);
+					unit+=16;
+					i2ob_dev_count++;
+
+					/* We want to know when device goes away */
+					i2o_device_notify_on(d, &i2o_block_handler);
 				}
-				else
-					printk(KERN_INFO "TID %d not claimed\n",dev->tid);
 			}
 			else
 			{
 				if(!warned++)
-					printk("i2o_block: too many device, registering only %d.\n", unit>>4);
+					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", unit>>4);
 			}
+			i2o_release_device(d, &i2o_block_handler);
 		}
 		i2o_unlock_controller(c);
 	}
-	i2ob_devices = unit;
 }
 
 /*
- *	Have we seen a media change ?
+ * New device notification handler.  Called whenever a new
+ * I2O block storage device is added to the system.
+ * 
+ * Should we spin lock around this to keep multiple devs from 
+ * getting updated at the same time? 
+ * 
  */
+void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d)
+{
+	struct i2ob_device *dev;
+	int unit = 0;
+
+	printk(KERN_INFO "i2o_block: New device detected\n");
+	printk(KERN_INFO "   Controller %d Tid %d\n",c->unit, d->lct_data.tid);
+
+	/* Check for available space */
+	if(i2ob_dev_count>=MAX_I2OB<<4)
+	{
+		printk(KERN_ERR "i2o_block: No more devices allowed!\n");
+		return;
+	}
+	for(unit = 0; unit < (MAX_I2OB<<4); unit += 16)
+	{
+		if(!i2ob_dev[unit].i2odev)
+			break;
+	}
+
+	/*
+	 * Creating a RAID 5 volume takes a little while and the UTIL_CLAIM
+	 * will fail if we don't give the card enough time to do it's magic, 
+	 * so we just sleep for a little while and let it do it's thing
+	 */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(10*HZ);
+
+	if(i2o_claim_device(d, &i2o_block_handler))
+	{
+		printk(KERN_INFO 
+			"i2o_block: Unable to claim device. Installation aborted\n");
+		return;
+	}
+
+	dev = &i2ob_dev[unit];
+	dev->i2odev = d; 
+	dev->controller = c;
+	dev->tid = d->lct_data.tid;
+
+	if(i2ob_install_device(c,d,unit))
+		printk(KERN_ERR "i2o_block: Could not install new device\n");
+	else	
+	{
+		i2ob_dev_count++;
+		i2o_device_notify_on(d, &i2o_block_handler);
+	}
+
+	i2o_release_device(d, &i2o_block_handler);
  
+	return;
+}
+
+/*
+ * Deleted device notification handler.  Called when a device we
+ * are talking to has been deleted by the user or some other
+ * mysterious fource outside the kernel.
+ */
+void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d)
+{	
+	int unit = 0;
+	int i = 0;
+	int flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	/*
+	 * Need to do this...we somtimes get two events from the IRTOS
+	 * in a row and that causes lots of problems.
+	 */
+	i2o_device_notify_off(d, &i2o_block_handler);
+
+	printk(KERN_INFO "I2O Block Device Deleted\n");
+
+	for(unit = 0; unit < MAX_I2OB<<4; unit += 16)
+	{
+		if(i2ob_dev[unit].i2odev == d)
+		{
+			printk(KERN_INFO "  /dev/%s: Controller %d Tid %d\n", 
+				d->dev_name, c->unit, d->lct_data.tid);
+			break;
+		}
+	}
+	if(unit >= MAX_I2OB<<4)
+	{
+		printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n");
+		return;
+	}
+
+	/* 
+	 * This will force errors when i2ob_get_queue() is called
+	 * by the kenrel.
+	 */
+	i2ob_dev[unit].req_queue = NULL;
+	for(i = unit; i <= unit+15; i++)
+	{
+		i2ob_dev[i].i2odev = NULL;
+		i2ob_sizes[i] = 0;
+		i2ob_hardsizes[i] = 0;
+		i2ob_max_sectors[i] = 0;
+		i2ob[i].nr_sects = 0;
+		i2ob_gendisk.part[i].nr_sects = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/*
+	 * Sync the device...this will force all outstanding I/Os
+	 * to attempt to complete, thus causing error messages.
+	 * We have to do this as the user could immediatelly create
+	 * a new volume that gets assigned the same minor number.
+	 * If there are still outstanding writes to the device,
+	 * that could cause data corruption on the new volume!
+	 *
+	 * The truth is that deleting a volume that you are currently
+	 * accessing will do _bad things_ to your system.  This 
+	 * handler will keep it from crashing, but must probably 
+	 * you'll have to do a 'reboot' to get the system running
+	 * properly.  Deleting disks you are using is dumb.  
+	 * Umount them first and all will be good!
+	 *
+	 * It's not this driver's job to protect the system from
+	 * dumb user mistakes :)
+	 */
+	if(i2ob_dev[unit].refcnt)
+		fsync_dev(MKDEV(MAJOR_NR,unit));
+
+	/*
+	 * Decrease usage count for module
+	 */	
+	while(i2ob_dev[unit].refcnt--)
+		MOD_DEC_USE_COUNT;
+
+	i2ob_dev[unit].refcnt = 0;
+	
+	i2ob_dev[i].tid = 0;
+
+	/* 
+	 * Do we need this?
+	 * The media didn't really change...the device is just gone
+	 */
+	i2ob_media_change_flag[unit] = 1;
+
+	i2ob_dev_count--;	
+
+	return;
+}
+
+/*
+ *	Have we seen a media change ?
+ */
 static int i2ob_media_change(kdev_t dev)
 {
 	int i=MINOR(dev);
@@ -960,12 +1517,14 @@
 	return do_i2ob_revalidate(dev, 0);
 }
 
-static int i2ob_reboot_event(struct notifier_block *n, unsigned long code, void *p)
+/*
+ * Reboot notifier.  This is called by i2o_core when the system
+ * shuts down.
+ */
+static void i2ob_reboot_event(void)
 {
 	int i;
 	
-	if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
-		return NOTIFY_DONE;
 	for(i=0;i<MAX_I2OB;i++)
 	{
 		struct i2ob_device *dev=&i2ob_dev[(i<<4)];
@@ -973,8 +1532,7 @@
 		if(dev->refcnt!=0)
 		{
 			/*
-			 *	Flush the onboard cache on power down
-			 *	also unlock the media
+			 *	Flush the onboard cache
 			 */
 			u32 msg[5];
 			int *query_done = &dev->done_flag;
@@ -984,6 +1542,7 @@
 			msg[3] = (u32)query_done;
 			msg[4] = 60<<16;
 			i2o_post_wait(dev->controller, msg, 20, 2);
+
 			/*
 			 *	Unlock the media
 			 */
@@ -995,25 +1554,18 @@
 			i2o_post_wait(dev->controller, msg, 20, 2);
 		}
 	}	
-	return NOTIFY_DONE;
 }
 
-struct notifier_block i2ob_reboot_notifier =
-{
-	i2ob_reboot_event,
-	NULL,
-	0
-};
-
 static struct block_device_operations i2ob_fops =
 {
-	open:			i2ob_open,
-	release:		i2ob_release,
-	ioctl:			i2ob_ioctl,
-	check_media_change:	i2ob_media_change,
-	revalidate:		i2ob_revalidate,
+   open:       i2ob_open,
+   release:    i2ob_release,
+   ioctl:         i2ob_ioctl,
+   check_media_change:  i2ob_media_change,
+   revalidate:    i2ob_revalidate,
 };
-	
+
+
 static struct gendisk i2ob_gendisk = 
 {
 	MAJOR_NR,
@@ -1027,6 +1579,7 @@
 	NULL
 };
 
+
 /*
  * And here should be modules and kernel interface 
  *  (Just smiley confuses emacs :-)
@@ -1040,19 +1593,20 @@
 {
 	int i;
 
-	printk(KERN_INFO "I2O Block Storage OSM v0.07. (C) 1999 Red Hat Software.\n");
+	printk(KERN_INFO "I2O Block Storage OSM v0.9\n");
+	printk(KERN_INFO "   (c) Copyright 1999, 2000 Red Hat Software.\n");
 	
 	/*
 	 *	Register the block device interfaces
 	 */
 
 	if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) {
-		printk("Unable to get major number %d for i2o_block\n",
+		printk(KERN_ERR "Unable to get major number %d for i2o_block\n",
 		       MAJOR_NR);
 		return -EIO;
 	}
 #ifdef MODULE
-	printk("i2o_block: registered device at major %d\n", MAJOR_NR);
+	printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR);
 #endif
 
 	/*
@@ -1063,6 +1617,7 @@
 	hardsect_size[MAJOR_NR] = i2ob_hardsizes;
 	blk_size[MAJOR_NR] = i2ob_sizes;
 	max_sectors[MAJOR_NR] = i2ob_max_sectors;
+	blk_dev[MAJOR_NR].queue = i2ob_get_queue;
 	
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request);
 	blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
@@ -1082,17 +1637,11 @@
 	/*
 	 *	Set up the queue
 	 */
-	
-	for(i = 0; i< MAX_I2OB_DEPTH; i++)
+	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
 	{
-		i2ob_queue[i].next = &i2ob_queue[i+1];
-		i2ob_queue[i].num = i;
+		i2ob_queues[i] = NULL;
 	}
-	
-	/* Queue is MAX_I2OB + 1... */
-	i2ob_queue[i].next = NULL;
-	i2ob_qhead = &i2ob_queue[0];
-	
+
 	/*
 	 *	Timers
 	 */
@@ -1115,15 +1664,26 @@
 	i2ob_context = i2o_block_handler.context;	 
 
 	/*
-	 *	Finally see what is actually plugged in to our controllers
+	 * Initialize event handling thread
 	 */
+	init_MUTEX_LOCKED(&i2ob_evt_sem);
+	evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND);
+	if(evt_pid < 0)
+	{
+		printk(KERN_ERR 
+			"i2o_block: Could not initialize event thread.  Aborting\n");
+		i2o_remove_handler(&i2o_block_handler);
+		return 0;
+	}
 
+	/*
+	 *	Finally see what is actually plugged in to our controllers
+	 */
 	for (i = 0; i < MAX_I2OB; i++)
 		register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4,
 			&i2ob_fops, 0);
 	i2ob_probe();
 	
-	register_reboot_notifier(&i2ob_reboot_notifier);
 	return 0;
 }
 
@@ -1136,8 +1696,21 @@
 void cleanup_module(void)
 {
 	struct gendisk **gdp;
+	int i;
 	
-	unregister_reboot_notifier(&i2ob_reboot_notifier);
+	/*
+	 * Unregister for updates from any devices..otherwise we still
+	 * get them and the core jumps to random memory :O
+	 */
+	if(i2ob_dev_count) {
+		struct i2o_device *d;
+		for(i = 0; i < MAX_I2OB; i++)
+		if((d=i2ob_dev[i<<4].i2odev)) {
+			i2o_device_notify_off(d, &i2o_block_handler);
+			i2o_event_register(d->controller, d->lct_data.tid, 
+				i2ob_context, i<<4, 0);
+		}
+	}
 	
 	/*
 	 *	Flush the OSM
@@ -1150,6 +1723,21 @@
 	 */
 	if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
 		printk("i2o_block: cleanup_module failed\n");
+
+	if(evt_running) {
+		i = kill_proc(evt_pid, SIGTERM, 1);
+		if(!i) {
+			int count = 5 * 100;
+			while(evt_running && --count) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+	
+			if(!count)
+				printk(KERN_ERR "Giving up on i2oblock thread...\n");	
+		}
+	}
+
 
 	/*
 	 *	Why isnt register/unregister gendisk in the kernel ???
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.3.99-pre5/linux/drivers/i2o/i2o_config.c	Thu Feb 10 17:11:09 2000
+++ linux/drivers/i2o/i2o_config.c	Fri Apr 21 16:08:52 2000
@@ -85,11 +85,21 @@
 {
 	u32 *msg = (u32 *)m;
 
-	if (msg[0] & (1<<13))
+	if (msg[0] & MSG_FAIL) {
+		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
+
 		printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
-        
-	if (msg[4] >> 24)  // RegStatus != SUCCESS
-		i2o_report_status(KERN_INFO,"i2o_config",msg);
+
+		/* Release the preserved msg frame by resubmitting it as a NOP */
+
+		preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+		preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+		preserved_msg[2] = 0;
+		i2o_post_message(c, msg[7]);
+	}
+
+	if (msg[4] >> 24)  // ReqStatus != SUCCESS
+		i2o_report_status(KERN_INFO,"i2o_config", msg);
 
 	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
 	{
@@ -166,6 +176,9 @@
 struct i2o_handler cfg_handler=
 {
 	i2o_cfg_reply,
+	NULL,
+	NULL,
+	NULL,
 	"Configuration",
 	0,
 	0xffffffff	// All classes
@@ -409,14 +422,14 @@
 		return -ENOMEM;
 	}
 
-        len = i2o_issue_params(i2o_cmd, c, kcmd.tid, 
-       			ops, kcmd.oplen, res, 65536);
-        i2o_unlock_controller(c);
+	len = i2o_issue_params(i2o_cmd, c, kcmd.tid, 
+				ops, kcmd.oplen, res, 65536);
+	i2o_unlock_controller(c);
 	kfree(ops);
         
 	if (len < 0) {
 		kfree(res);
-		return len; /* -DetailedStatus */
+		return -EAGAIN;
 	}
 
 	put_user(len, kcmd.reslen);
@@ -749,7 +762,7 @@
 
 	/* Device exists? */
 	for(d = iop->devices; d; d = d->next)
-		if(d->lct_data->tid == kdesc.tid)
+		if(d->lct_data.tid == kdesc.tid)
 			break;
 
 	if(!d)
@@ -903,7 +916,7 @@
 #endif
 {
 	printk(KERN_INFO "I2O configuration manager v 0.04.\n");
-	printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software");
+	printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software\n");
 	
 	if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL)
 	{
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.99-pre5/linux/drivers/i2o/i2o_core.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/i2o/i2o_core.c	Fri Apr 21 16:08:52 2000
@@ -2,7 +2,7 @@
  * Core I2O structure managment 
  * 
  * (C) Copyright 1999   Red Hat Software 
- *	
+ *
  * Written by Alan Cox, Building Number Three Ltd 
  * 
  * This program is free software; you can redistribute it and/or 
@@ -12,12 +12,13 @@
  * 
  * A lot of the I2O message side code from this is taken from the 
  * Red Creek RCPCI45 adapter driver by Red Creek Communications 
- *
+ * 
  * Fixes by: 
  *		Philipp Rumpf 
  *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
  *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
  *		Deepak Saxena <deepak@plexity.net> 
+ * 
  */
 
 #include <linux/config.h>
@@ -31,51 +32,73 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/spinlock.h>
+#include <linux/smp_lock.h>
 
 #include <linux/bitops.h>
 #include <linux/wait.h>
+#include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/semaphore.h>
 
 #include <asm/io.h>
+#include <linux/reboot.h>
 
 #include "i2o_lan.h"
 
 // #define DRIVERDEBUG
-// #define DEBUG_IRQ
 
-#define dprintk(x)
+#ifdef DRIVERDEBUG
+#define dprintk(s, args...) printk(s, ## args)
+#else
+#define dprintk(s, args...)
+#endif
 
-/*
- *	Size of the I2O module table
- */
- 
-static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
-static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
-struct i2o_controller *i2o_controller_chain;
+/* OSM table */
+static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES] = {NULL};
+
+/* Controller list */
+static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS] = {NULL};
+struct i2o_controller *i2o_controller_chain = NULL;
 int i2o_num_controllers = 0;
+
+/* Initiator Context for Core message */
 static int core_context = 0;
 
-static int i2o_activate_controller(struct i2o_controller *iop);
-static int i2o_online_controller(struct i2o_controller *c);
-static int i2o_init_outbound_q(struct i2o_controller *c);
+/* Initialization && shutdown functions */
+static void i2o_sys_init(void);
+static void i2o_sys_shutdown(void);
+static int i2o_clear_controller(struct i2o_controller *);
+static int i2o_reboot_event(struct notifier_block *, unsigned long , void *);
+static int i2o_online_controller(struct i2o_controller *);
+static int i2o_init_outbound_q(struct i2o_controller *);
+static int i2o_post_outbound_messages(struct i2o_controller *);
+static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
+
+/* Reply handler */
 static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
 			   struct i2o_message *);
-static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
-static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
-void i2o_dump_message(u32 *msg);
-
-static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
 
-static int i2o_reset_controller(struct i2o_controller *);
+/* Various helper functions */
 static int i2o_lct_get(struct i2o_controller *);
+static int i2o_lct_notify(struct i2o_controller *);
 static int i2o_hrt_get(struct i2o_controller *);
 
-static void i2o_sys_init(void);
-static void i2o_sys_shutdown(void);
-
 static int i2o_build_sys_table(void);
 static int i2o_systab_send(struct i2o_controller *c);
 
+/* I2O core event handler */
+static int i2o_core_evt(void *);
+static int evt_pid;
+static int evt_running;
+
+/* Dynamic LCT update handler */
+static int i2o_dyn_lct(void *);
+
+void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *);
+
 /*
  * I2O System Table.  Contains information about
  * all the IOPs in the system.  Used to inform IOPs
@@ -126,65 +149,154 @@
 static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;
 static void i2o_post_wait_complete(u32, int);
 
-/* Message handler */ 
+/* OSM descriptor handler */ 
 static struct i2o_handler i2o_core_handler =
 {
 	(void *)i2o_core_reply,
+	NULL,
+	NULL,
+	NULL,
 	"I2O core layer",
-	0
+	0,
+	I2O_CLASS_EXECUTIVE
 };
 
 
 /*
- *	I2O configuration spinlock. This isnt a big deal for contention
- *	so we have one only
+ * Used when queing a reply to be handled later
+ */
+struct reply_info
+{
+	struct i2o_controller *iop;
+	u32 msg[MSG_FRAME_SIZE];
+};
+static struct reply_info evt_reply;
+static struct reply_info events[I2O_EVT_Q_LEN];
+static int evt_in = 0;
+static int evt_out = 0;
+static int evt_q_len = 0;
+#define MODINC(x,y) (x = x++ % y)
+
+/*
+ * I2O configuration spinlock. This isnt a big deal for contention
+ * so we have one only
  */
- 
 static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED;
 
+/* 
+ * Event spinlock.  Used to keep event queue sane and from
+ * handling multiple events simultaneously.
+ */
+static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Semaphore used to syncrhonize event handling thread with 
+ * interrupt handler.
+ */
+DECLARE_MUTEX(evt_sem);
+DECLARE_WAIT_QUEUE_HEAD(evt_wait);
+
+static struct notifier_block i2o_reboot_notifier =
+{
+        i2o_reboot_event,
+        NULL,
+        0
+};
+
+
 /*
  * I2O Core reply handler
- *
- * Only messages this should see are i2o_post_wait() replies
  */
 void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
 		    struct i2o_message *m)
 {
 	u32 *msg=(u32 *)m;
-	int status;
+	u32 status;
 	u32 context = msg[2];
 
 #if 0
 	i2o_report_status(KERN_INFO, "i2o_core", msg);
 #endif
-	
+
 	if (msg[0] & (1<<13)) // Fail bit is set
-        {
-                printk(KERN_ERR "%s: Failed to process the msg:\n",c->name);
-                printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
-		       (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
-		       0xFFF);
-                printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n"
-		       "LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
-		       msg[4] >> 24, (msg[4] >> 16) & 0xFF,
-		       (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
-                printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
-		       msg[5] >> 16, msg[5] & 0xFFF);
-                return;
-        }
+	{
+		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
+
+//		i2o_report_failure(KERN_INFO, c, "i2o_core", msg);
+		printk(KERN_ERR "%s: Failed to process the msg:\n", c->name);
+		printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =% d\n",
+			(msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
+		printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n"
+			"LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
+			msg[4] >> 24, (msg[4] >> 16) & 0xFF,
+			(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+		printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
+			msg[5] >> 16, msg[5] & 0xFFF);
+
+		/* If the failed request needs special treatment,
+		 * it should be done here. */
+
+                /* Release the preserved msg by resubmitting it as a NOP */
+
+		preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+		preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+		preserved_msg[2] = 0;
+		i2o_post_message(c, msg[7]);
+
+		/* If reply to i2o_post_wait failed, return causes a timeout */
+		return;
+	}       
 
 	if(msg[2]&0x80000000)	// Post wait message
 	{
 		if (msg[4] >> 24)
 		{
-			i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
+			i2o_report_status(KERN_INFO, "i2o_core: post_wait reply", msg);
 			status = -(msg[4] & 0xFFFF);
 		}
 		else
 			status = I2O_POST_WAIT_OK;
 	
 		i2o_post_wait_complete(context, status);
+		return;
+	}
+
+	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
+	{
+		memcpy(events[evt_in].msg, msg, MSG_FRAME_SIZE);
+		events[evt_in].iop = c;
+
+		spin_lock(&i2o_evt_lock);
+		MODINC(evt_in, I2O_EVT_Q_LEN);
+		if(evt_q_len == I2O_EVT_Q_LEN)
+			MODINC(evt_out, I2O_EVT_Q_LEN);
+		else
+			evt_q_len++;
+		spin_unlock(&i2o_evt_lock);
+
+		up(&evt_sem);
+		wake_up_interruptible(&evt_wait);
+		return;
+	}
+
+	if(m->function == I2O_CMD_LCT_NOTIFY)
+	{
+		up(&c->lct_sem);
+		return;
 	}
+
+	/*
+	 * If this happens, we want to dump the message to the syslog so
+	 * it can be sent back to the card manufacturer by the end user
+	 * to aid in debugging.
+	 * 
+	 */
+	printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
+			"Message dumped to syslog\n", 
+			c->name);
+	i2o_dump_message(msg);
+
+	return;
 }
 
 /*
@@ -218,8 +330,9 @@
 	
 
 /*
- *	Each I2O controller has a chain of devices on it - these match
- *	the useful parts of the LCT of the board.
+ *	Each I2O controller has a chain of devices on it.
+ * Each device has a pointer to it's LCT entry to be used
+ * for fun purposes.
  */
  
 int i2o_install_device(struct i2o_controller *c, struct i2o_device *d)
@@ -245,19 +358,43 @@
 int __i2o_delete_device(struct i2o_device *d)
 {
 	struct i2o_device **p;
+	int i;
 
 	p=&(d->controller->devices);
 
 	/*
 	 *	Hey we have a driver!
+	 * Check to see if the driver wants us to notify it of 
+	 * device deletion. If it doesn't we assume that it
+	 * is unsafe to delete a device with an owner and 
+	 * fail.
 	 */
-	 
 	if(d->owner)
-		return -EBUSY;
+	{
+		if(d->owner->dev_del_notify)
+		{
+			dprintk(KERN_INFO "Device has owner, notifying\n");
+			d->owner->dev_del_notify(d->controller, d);
+			if(d->owner)
+			{
+				printk(KERN_WARNING 
+					"Driver \"%s\" did not release device!\n", d->owner->name);
+				return -EBUSY;
+			}
+		}
+		else
+			return -EBUSY;
+	}
 
 	/*
-	 *	Seek, locate
+	 * Tell any other users who are talking to this device
+	 * that it's going away.  We assume that everything works.
 	 */
+	for(i=0; i < I2O_MAX_MANAGERS; i++)
+	{
+		if(d->managers[i] && d->managers[i]->dev_del_notify)
+			d->managers[i]->dev_del_notify(d->controller, d);
+	}
 	 			
 	while(*p!=NULL)
 	{
@@ -282,6 +419,10 @@
 
 	spin_lock(&i2o_configuration_lock);
 
+	/*
+	 *	Seek, locate
+	 */
+
 	ret = __i2o_delete_device(d);
 
 	spin_unlock(&i2o_configuration_lock);
@@ -302,12 +443,18 @@
 		if(i2o_controllers[i]==NULL)
 		{
 			i2o_controllers[i]=c;
+			c->devices = NULL;
 			c->next=i2o_controller_chain;
 			i2o_controller_chain=c;
 			c->unit = i;
-
+			c->page_frame = NULL;
+			c->hrt = NULL;
+			c->lct = NULL;
+			c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL);
+			c->status_block = NULL;
 			sprintf(c->name, "i2o/iop%d", i);
 			i2o_num_controllers++;
+			init_MUTEX_LOCKED(&c->lct_sem);
 			spin_unlock(&i2o_configuration_lock);
 			return 0;
 		}
@@ -322,12 +469,21 @@
 	struct i2o_controller **p;
 	int users;
 	char name[16];
+	int stat;
+
+	dprintk(KERN_INFO "Deleting controller iop%d\n", c->unit);
+
+	/*
+	 * Clear event registration as this can cause weird behavior
+	 */
+	if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
+		i2o_event_register(c, core_context, 0, 0, 0);
 
 	spin_lock(&i2o_configuration_lock);
 	if((users=atomic_read(&c->users)))
 	{
-		printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users);
-		c->bus_disable(c); 
+		dprintk(KERN_INFO "I2O: %d users for controller iop%d\n", users,
+			c->name);
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
 	}
@@ -336,20 +492,40 @@
 		if(__i2o_delete_device(c->devices)<0)
 		{
 			/* Shouldnt happen */
-			c->bus_disable(c); 
+			c->bus_disable(c);
 			spin_unlock(&i2o_configuration_lock);
 			return -EBUSY;
 		}
 	}
 
+	/*
+	 * If this is shutdown time, the thread's already been killed
+	 */
+	if(c->lct_running) {
+		stat = kill_proc(c->lct_pid, SIGTERM, 1);
+		if(!stat) {
+			int count = 10 * 100;
+			while(c->lct_running && --count) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+		
+			if(!count)
+				printk(KERN_ERR 
+					"%s: LCT thread still running!\n", 
+					c->name);
+		}
+	}
+
 	p=&i2o_controller_chain;
 
 	while(*p)
 	{
 		if(*p==c)
 		{
-			/* Ask the IOP to switch into RESET state */
-			i2o_reset_controller(c);
+			/* Ask the IOP to switch to HOLD state */
+			if (i2o_clear_controller(c) < 0)
+				printk(KERN_ERR "Unable to clear iop%d\n", c->unit);
 
 			/* Release IRQ */
 			c->destructor(c);
@@ -365,14 +541,15 @@
 				kfree(c->lct);
 			if(c->status_block)
 				kfree(c->status_block);
+			if(c->dlct)
+				kfree(c->dlct);
 
 			i2o_controllers[c->unit]=NULL;
 			memcpy(name, c->name, strlen(c->name)+1);
 			kfree(c);
-			i2o_num_controllers--;
+			dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name);
 			
-			dprintk((KERN_INFO "%s: Deleted from controller chain.\n", name));
-
+			i2o_num_controllers--;
 			return 0;
 		}
 		p=&((*p)->next);
@@ -404,105 +581,86 @@
 	
 
 /*
- * Claim a device for use as either the primary user or just
- * as a management/secondary user
+ * Claim a device for use by an OSM
  */
-int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
+int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h)
 {
-	/* Device already has a primary user or too many managers */
-	if((type == I2O_CLAIM_PRIMARY && d->owner) ||
-		(d->num_managers == I2O_MAX_MANAGERS))
-	{
-			return -EBUSY;
-	}
-
-	if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, type))
+	spin_lock(&i2o_configuration_lock);
+	if(d->owner)
 	{
+		printk(KERN_INFO "issue claim called, but dev as owner!");
+		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
 	}
 
-	spin_lock(&i2o_configuration_lock);
-	if(d->owner)
+	if(i2o_issue_claim(d->controller,d->lct_data.tid, h->context, 1,
+		 I2O_CLAIM_PRIMARY))
 	{
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
 	}
-	atomic_inc(&d->controller->users);
-
-	if(type == I2O_CLAIM_PRIMARY)
-		d->owner=h;
-	else
-		if (i2o_add_management_user(d, h))
-			printk(KERN_WARNING "i2o: Too many managers for TID %d\n",
-				d->lct_data->tid);
-									       
 
+	d->owner=h;
 	spin_unlock(&i2o_configuration_lock);
 	return 0;
 }
 
-int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
+/*
+ * Release a device that the OS is using
+ */
+int i2o_release_device(struct i2o_device *d, struct i2o_handler *h)
 {
 	int err = 0;
 
 	spin_lock(&i2o_configuration_lock);
-
-	/* Primary user */
-	if(type == I2O_CLAIM_PRIMARY)
+	if(d->owner != h)
 	{
-		if(d->owner != h)
-			err = -ENOENT;
-		else
-		{
-			if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0,
-					   type))
-			{
-				err = -ENXIO;
-			}
-			else
-			{
-				d->owner = NULL;
-				atomic_dec(&d->controller->users);
-			}
-		}
-
 		spin_unlock(&i2o_configuration_lock);
-		return err;
-	}
+		return -ENOENT;
+	}	
 
-	/* Management or other user */
-	if(i2o_remove_management_user(d, h))
-		err = -ENOENT;
-	else
+	if(i2o_issue_claim(d->controller, d->lct_data.tid, h->context, 0,
+			I2O_CLAIM_PRIMARY))
 	{
-		atomic_dec(&d->controller->users);
-
-		if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0, 
-				   type))
-			err = -ENXIO;
+		err = -ENXIO;
 	}
 
+	d->owner = NULL;
+
 	spin_unlock(&i2o_configuration_lock);
 	return err;
 }
 
-int i2o_add_management_user(struct i2o_device *d, struct i2o_handler *h)
+/*
+ * Called by OSMs to let the core know that they want to be
+ * notified if the given device is deleted from the system.
+ */
+int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h)
 {
 	int i;
 
 	if(d->num_managers == I2O_MAX_MANAGERS)
-		return 1;
+		return -ENOSPC;
 
 	for(i = 0; i < I2O_MAX_MANAGERS; i++)
+	{
 		if(!d->managers[i])
+		{
 			d->managers[i] = h;
+			break;
+		}
+	}
 	
 	d->num_managers++;
 	
 	return 0;
 }
 
-int i2o_remove_management_user(struct i2o_device *d, struct i2o_handler *h)
+/*
+ * Called by OSMs to let the core know that they no longer
+ * are interested in the fate of the given device.
+ */
+int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h)
 {
 	int i;
 
@@ -511,6 +669,7 @@
 		if(d->managers[i] == h)
 		{
 			d->managers[i] = NULL;
+			d->num_managers--;
 			return 0;
 		}
 	}
@@ -519,6 +678,304 @@
 }
 
 /*
+ * Event registration API
+ */
+int i2o_event_register(struct i2o_controller *c, u32 tid, 
+		u32 init_context, u32 tr_context, u32 evt_mask)
+{
+	u32 msg[5];	// Not performance critical, so we just 
+					// i2o_post_this it instead of building it
+					// in IOP memory
+	
+	msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid;
+	msg[2] = (u32)init_context;
+	msg[3] = (u32)tr_context;
+	msg[4] = evt_mask;
+
+	return i2o_post_this(c, msg, sizeof(msg));
+}
+
+/*
+ * Event ack API
+ *
+ * We just take a pointer to the original UTIL_EVENT_REGISTER reply
+ * message and change the function code since that's what spec
+ * describes an EventAck message looking like.
+ */
+int i2o_event_ack(struct i2o_controller *c, u32 *msg)
+{
+	struct i2o_message *m = (struct i2o_message *)msg;
+
+	m->function = I2O_CMD_UTIL_EVT_ACK;
+
+	return i2o_post_wait(c, msg, m->size * 4, 2);
+}
+
+/*
+ * Core event handler.  Runs as a separate thread and is woken
+ * up whenever there is an Executive class event.
+ */
+static int i2o_core_evt(void *reply_data)
+{
+	struct reply_info *reply = (struct reply_info *) reply_data;
+	u32 *msg = reply->msg;
+	struct i2o_controller *c = NULL;
+	int flags;
+
+	lock_kernel();
+	exit_files(current);
+	daemonize();
+	unlock_kernel();
+
+	strcpy(current->comm, "i2oevtd");
+	evt_running = 1;
+
+	while(1)
+	{
+		down_interruptible(&evt_sem);
+		if(signal_pending(current))
+		{
+			dprintk(KERN_INFO "I2O event thread dead\n");
+			evt_running = 0;
+			return 0;	
+		}
+
+		/* 
+		 * Copy the data out of the queue so that we don't have to lock
+		 * around the whole function and just around the qlen update
+		 */
+		spin_lock_irqsave(&i2o_evt_lock, flags);
+		memcpy(reply, &events[evt_out], sizeof(struct reply_info));
+		MODINC(evt_out, I2O_EVT_Q_LEN);
+		evt_q_len--;
+		spin_unlock_irqrestore(&i2o_evt_lock, flags);
+	
+		c = reply->iop;
+	 	dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]);
+
+		/* 
+		 * We do not attempt to delete/quiesce/etc. the controller if
+		 * some sort of error indidication occurs.  We may want to do
+		 * so in the future, but for now we just let the user deal with 
+		 * it.  One reason for this is that what to do with an error
+		 * or when to send what ærror is not really agreed on, so
+		 * we get errors that may not be fatal but just look like they
+		 * are...so let the user deal with it.
+		 */
+		switch(msg[4])
+		{
+			case I2O_EVT_IND_EXEC_RESOURCE_LIMITS:
+				printk(KERN_ERR "iop%d: Out of resources\n", c->unit);
+				break;
+
+			case I2O_EVT_IND_EXEC_POWER_FAIL:
+				printk(KERN_ERR "iop%d: Power failure\n", c->unit);
+				break;
+
+			case I2O_EVT_IND_EXEC_HW_FAIL:
+			{
+				char *fail[] = 
+					{ 
+						"Unknown Error",
+						"Power Lost",
+						"Code Violation",
+						"Parity Error",
+						"Code Execution Exception",
+						"Watchdog Timer Expired" 
+					};
+
+				if(msg[5] <= 6)
+					printk(KERN_ERR "%s: Hardware Failure: %s\n", 
+						c->name, fail[msg[5]]);
+				else
+					printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name);
+
+				break;
+			}
+
+			/*
+		 	 * New device created
+		 	 * - Create a new i2o_device entry
+		 	 * - Inform all interested drivers about this device's existence
+		 	 */
+			case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY:
+			{
+				struct i2o_device *d = (struct i2o_device *)
+					kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+				int i;
+
+				memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry));
+	
+				d->next = NULL;
+				d->controller = c;
+				d->flags = 0;
+	
+				i2o_report_controller_unit(c, d);
+				i2o_install_device(c,d);
+	
+				for(i = 0; i < MAX_I2O_MODULES; i++)
+				{
+					if(i2o_handlers[i] && 
+						i2o_handlers[i]->new_dev_notify &&
+						(i2o_handlers[i]->class&d->lct_data.class_id))
+						i2o_handlers[i]->new_dev_notify(c,d);
+				}
+			
+				break;
+			}
+	
+			/*
+ 		 	 * LCT entry for a device has been modified, so update it
+		 	 * internally.
+		 	 */
+			case I2O_EVT_IND_EXEC_MODIFIED_LCT:
+			{
+				struct i2o_device *d;
+				i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5];
+
+				for(d = c->devices; d; d = d->next)
+				{
+					if(d->lct_data.tid == new_lct->tid)
+					{
+						memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry));
+						break;
+					}
+				}
+				break;
+			}
+	
+			case I2O_EVT_IND_CONFIGURATION_FLAG:
+				printk(KERN_WARNING "%s requires user configuration\n", c->name);
+				break;
+	
+			case I2O_EVT_IND_GENERAL_WARNING:
+				printk(KERN_WARNING "%s: Warning notification received!"
+					"Check configuration for errors!\n", c->name);
+				break;
+	
+			default:
+				printk(KERN_WARNING "%s: Unknown event (0x%08x)...check config\n", c->name, msg[4]);
+				break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Dynamic LCT update.  This compares the LCT with the currently
+ * installed devices to check for device deletions..this needed b/c there
+ * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so
+ * we can't just have the event handler do this...annoying
+ *
+ * This is a hole in the spec that will hopefully be fixed someday.
+ */
+static int i2o_dyn_lct(void *foo)
+{
+	struct i2o_controller *c = (struct i2o_controller *)foo;
+	struct i2o_device *d = NULL;
+	struct i2o_device *d1 = NULL;
+	int i = 0;
+	int found = 0;
+	int entries;
+	void *tmp;
+	char name[16];
+
+	lock_kernel();
+	exit_files(current);
+	daemonize();
+	unlock_kernel();
+
+	sprintf(name, "iop%d_lctd", c->unit);
+	strcpy(current->comm, name);	
+	
+	c->lct_running = 1;
+
+	while(1)
+	{
+		down_interruptible(&c->lct_sem);
+		if(signal_pending(current))
+		{
+			dprintk(KERN_ERR "%s: LCT thread dead\n", c->name);
+			c->lct_running = 0;
+			return 0;
+		}
+
+		entries = c->dlct->table_size;
+		entries -= 3;
+		entries /= 9;
+
+		dprintk(KERN_INFO "I2O: Dynamic LCT Update\n");
+		dprintk(KERN_INFO "I2O: Dynamic LCT contains %d entries\n", entries);
+
+		if(!entries)
+		{
+			printk(KERN_INFO "iop%d: Empty LCT???\n", c->unit);
+			continue;
+		}
+
+		/*
+		 * Loop through all the devices on the IOP looking for their
+		 * LCT data in the LCT.  We assume that TIDs are not repeated.
+		 * as that is the only way to really tell.  It's been confirmed
+		 * by the IRTOS vendor(s?) that TIDs are not reused until they 
+		 * wrap arround(4096), and I doubt a system will up long enough
+		 * to create/delete that many devices.
+		 */
+		for(d = c->devices; d; )
+		{
+			found = 0;
+			d1 = d->next;
+			
+			for(i = 0; i < entries; i++) 
+			{ 
+				if(d->lct_data.tid == c->dlct->lct_entry[i].tid) 
+				{ 
+					found = 1; 
+					break; 
+				} 
+			} 
+			if(!found) 
+			{
+				dprintk(KERN_INFO "Deleted device!\n"); 
+				i2o_delete_device(d); 
+			} 
+			d = d1; 
+		}
+
+		/* 
+		 * Tell LCT to renotify us next time there is a change
+	 	 */
+		i2o_lct_notify(c);
+
+		/*
+		 * Copy new LCT into public LCT
+		 *
+		 * Possible race if someone is reading LCT while  we are copying 
+		 * over it. If this happens, we'll fix it then. but I doubt that
+		 * the LCT will get updated often enough or will get read by
+		 * a user often enough to worry.
+		 */
+		if(c->lct->table_size < c->dlct->table_size)
+		{
+			tmp = c->lct;
+			c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL);
+			if(!c->lct)
+			{
+				printk(KERN_ERR "%s: No memory for LCT!\n", c->name);
+				c->lct = tmp;
+				continue;
+			}
+			kfree(tmp);
+		}
+		memcpy(c->lct, c->dlct, c->dlct->table_size<<2);
+	}
+
+	return 0;
+}
+
+/*
  *	This is called by the bus specific driver layer when an interrupt
  *	or poll of this card interface is desired.
  */
@@ -527,41 +984,46 @@
 {
 	struct i2o_message *m;
 	u32 mv;
+	u32 *msg;
+	int count = 0;
 
-#ifdef DEBUG_IRQ
-	printk(KERN_INFO "%s: interrupt\n", c->name);
-#endif
-	/* Sometimes we get here, but a message can't be read. Why? */
+	/*
+	 * Old 960 steppings had a bug in the I2O unit that caused
+	 * the queue to appear empty when it wasn't.
+	 */
 	if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
 		mv=I2O_REPLY_READ32(c);
 
-	while (mv!=0xFFFFFFFF)
+	while(mv!=0xFFFFFFFF)
 	{
 		struct i2o_handler *i;
 		m=(struct i2o_message *)bus_to_virt(mv);
+		msg=(u32*)m;
+
+		count++;
+
 		/*
 		 *	Temporary Debugging
 		 */
 		if(m->function==0x15)
-			printk("UTFR!\n");
-
-#ifdef DEBUG_IRQ
-		i2o_dump_message((u32*)m);
-#endif
+			printk(KERN_ERR "%s: UTFR!\n", c->name);
 
 		i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
-		if(i)
+		if(i && i->reply)
 			i->reply(i,c,m);
 		else
 		{
-			printk("i2o: Spurious reply to handler %d\n", 
+			printk(KERN_WARNING "I2O: Spurious reply to handler %d\n", 
 				m->initiator_context&(MAX_I2O_MODULES-1));
-			i2o_dump_message((u32*)m);
 		}	
 	 	i2o_flush_reply(c,mv);
 		mb();
-		mv=I2O_REPLY_READ32(c);
-	}
+
+		/* That 960 bug again... */	
+		if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
+			mv=I2O_REPLY_READ32(c);
+
+	}		
 }
 
 
@@ -643,8 +1105,8 @@
 	{
 		if((jiffies-time)>=5*HZ)
 		{
-			dprintk((KERN_ERR "%s: Timeout waiting for message frame (%s).\n", 
-				c->name, why));
+			dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", 
+				c->name, why);
 			return 0xFFFFFFFF;
 		}
 		schedule();
@@ -667,8 +1129,8 @@
 	{
 		if(jiffies-time >= timeout*HZ )
 		{
-			dprintk((KERN_ERR "%s: timeout waiting for %s reply.\n",
-				c->name, why));
+			dprintk(KERN_ERR "%s: timeout waiting for %s reply.\n",
+				c->name, why);
 			return 0xFFFFFFFF;
 		}
 		schedule();
@@ -676,37 +1138,60 @@
 	return m;
 }
 	
-
 /*
  *	 Dump the information block associated with a given unit (TID)
  */
  
-void i2o_report_controller_unit(struct i2o_controller *c, int unit)
+void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d)
 {
 	char buf[64];
+	char str[22];
+	int ret;
+	int unit = d->lct_data.tid;
 	
-	if(i2o_query_scalar(c, unit, 0xF100, 3, buf, 16)>=0)
+	printk(KERN_INFO "Target ID %d.\n", unit);
+
+	if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0)
 	{
 		buf[16]=0;
-		printk(KERN_INFO "     Vendor: %s", buf);
+		printk(KERN_INFO "     Vendor: %s\n", buf);
 	}
-	if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)>=0)
+	if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0)
 	{
+
 		buf[16]=0;
-		printk("     Device: %s", buf);
+		printk(KERN_INFO "     Device: %s\n", buf);
 	}
 #if 0
 	if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
 	{
 		buf[16]=0;
-		printk("Description: %s", buf);
+		printk(KERN_INFO "     Description: %s\n", buf);
 	}
 #endif	
-	if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)>=0)
+	if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0)
 	{
 		buf[8]=0;
-		printk("        Rev: %s\n", buf);
+		printk(KERN_INFO "        Rev: %s\n", buf);
 	}
+
+	printk(KERN_INFO "    Class: ");
+	sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id));
+	printk("%s\n", str);
+		
+	printk(KERN_INFO "  Subclass: 0x%04X\n", d->lct_data.sub_class);
+	printk(KERN_INFO "     Flags: ");
+		
+	if(d->lct_data.device_flags&(1<<0))
+		printk("C");		// ConfigDialog requested
+	if(d->lct_data.device_flags&(1<<1))
+		printk("U");		// Multi-user capable
+	if(!(d->lct_data.device_flags&(1<<4)))
+		printk("P");		// Peer service enabled!
+	if(!(d->lct_data.device_flags&(1<<5)))
+		printk("M");		// Mgmt service enabled!
+	printk("\n");
+			
 }
 
 
@@ -723,20 +1208,21 @@
 static int i2o_parse_hrt(struct i2o_controller *c)
 {
 #ifdef DRIVERDEBUG
-	u32 *rows=(u32 *)c->hrt;
+	u32 *rows=(u32*)c->hrt;
 	u8 *p=(u8 *)c->hrt;
 	u8 *d;
 	int count;
 	int length;
 	int i;
 	int state;
-
-	if(p[3]!=0) {
+	
+	if(p[3]!=0)
+	{
 		printk(KERN_ERR "%s: HRT table for controller is too new a version.\n",
 			c->name);
-		return -1;	
+		return -1;
 	}
-	
+		
 	count=p[0]|(p[1]<<8);
 	length = p[2];
 	
@@ -803,7 +1289,6 @@
 		printk("\n");
 		rows+=length;
 	}
-
 #endif
 	return 0;
 }
@@ -818,21 +1303,19 @@
 	int i;
 	int max;
 	int tid;
-	u32 *p;
 	struct i2o_device *d;
-	char str[22];
 	i2o_lct *lct = c->lct;
 
 	if (lct == NULL) {
-		printk(KERN_ERR "%s: LCT is empty???\n",c->name);
+		printk(KERN_ERR "%s: LCT is empty???\n", c->name);
 		return -1;
 	}
-	
-	max = lct->table_size;	
+
+	max = lct->table_size;
 	max -= 3;
 	max /= 9;
-
-	printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max);
+	
+	printk(KERN_INFO "%s: LCT has %d entries.\n", c->name, max);
 	
 	if(lct->iop_flags&(1<<0))
 		printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
@@ -849,35 +1332,14 @@
 		d->controller = c;
 		d->next = NULL;
 
-		d->lct_data = &lct->lct_entry[i];
+		memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
 
 		d->flags = 0;
-		tid = d->lct_data->tid;
+		tid = d->lct_data.tid;
 		
-		printk(KERN_INFO "Target ID %d.\n", tid);
-
-		i2o_report_controller_unit(c, tid);
+		i2o_report_controller_unit(c, d);
 		
 		i2o_install_device(c, d);
-		
-		printk(KERN_INFO "     Class: ");
-		
-		sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id));
-		printk("%s", str);
-
-		printk(" Subclass: 0x%04X                Flags: ", 
-			d->lct_data->sub_class);
-
-		if(d->lct_data->device_flags&(1<<0))
-			printk("C");		// ConfigDialog requested
-		if(d->lct_data->device_flags&(1<<1))
-			printk("M");		// Multi-user capable
-		if(!(d->lct_data->device_flags&(1<<4)))
-			printk("P");		// Peer service enabled!
-		if(!(d->lct_data->device_flags&(1<<5)))
-			printk("m");		// Mgmt service enabled!
-		printk("\n");
-		p+=9;
 	}
 	return 0;
 }
@@ -892,59 +1354,66 @@
 	u32 msg[4];
 	int ret;
 
+	i2o_status_get(c);
+
 	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
 
 	if ((c->status_block->iop_state != ADAPTER_STATE_READY) &&
-	    (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
+		(c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
 	{
 		return 0;
 	}
 
-	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-	/* msg[2] filled in i2o_post_wait */
-	msg[3]=0;
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[3] = 0;
 
 	/* Long timeout needed for quiesce if lots of devices */
 
-	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120)))
-		printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n", 
+	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
+		printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n",
 			c->name, ret);
 	else
-		dprintk((KERN_INFO "%s: Quiesced.\n", c->name));
+		dprintk(KERN_INFO "%s: Quiesced.\n", c->name);
 
 	i2o_status_get(c); // Reread the Status Block
 
-	return ret;
+   return ret;
+
 }
 
-/* 
+/*
  * Enable IOP. Allows the IOP to resume external operations.
  */
 int i2o_enable_controller(struct i2o_controller *c)
 {
 	u32 msg[4];
 	int ret;
+
+	i2o_status_get(c);
 	
+	/* Enable only allowed on READY state */	
+	if(c->status_block->iop_state != ADAPTER_STATE_READY)
+		return -EINVAL;
+
 	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
-	/* msg[2] filled in i2o_post_wait */
 
-	/* How long of a timeout do we need? */
+   /* How long of a timeout do we need? */
 
 	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
-		printk(KERN_ERR "%s: Could not enable (status=%#10x).\n", 
+		printk(KERN_ERR "%s: Could not enable (status=%#10x).\n",
 			c->name, ret);
 	else
-		dprintk((KERN_INFO "%s: Enabled.\n", c->name));
+		dprintk(KERN_INFO "%s: Enabled.\n", c->name);
 
 	i2o_status_get(c);
 
 	return ret;
 }
 
-/* 
- * Clear an IOP to HOLD state, ie. terminate external operations, clear all 
+/*
+ * Clear an IOP to HOLD state, ie. terminate external operations, clear all
  * input queues and prepare for a system restart. IOP's internal operation
  * continues normally and the outbound queue is alive.
  * IOP is not expected to rebuild its LCT.
@@ -962,14 +1431,13 @@
 
 	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
-	/* msg[2] filled in i2o_post_wait */
 	msg[3]=0;
 
 	if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
-		printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n", 
+		printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n",
 			c->name, ret);
 	else
-		dprintk((KERN_INFO "%s: Cleared.\n",c->name));
+		dprintk(KERN_INFO "%s: Cleared.\n",c->name);
 
 	i2o_status_get(c);
 
@@ -977,21 +1445,21 @@
 
 	for (iop = i2o_controller_chain; iop; iop = iop->next)
 		if (iop != c)
-			i2o_enable_controller(iop);		
+			i2o_enable_controller(iop);
 
 	return ret;
 }
 
 
-/* 
- * Reset the IOP into INIT state and wait until IOP gets into RESET state.  
- * Terminate all external operations, clear IOP's inbound and outbound 
- * queues, terminate all DDMs, and reload the IOP's operating environment 
+/*
+ * Reset the IOP into INIT state and wait until IOP gets into RESET state.
+ * Terminate all external operations, clear IOP's inbound and outbound
+ * queues, terminate all DDMs, and reload the IOP's operating environment
  * and all local DDMs. IOP rebuilds its LCT.
  */
 static int i2o_reset_controller(struct i2o_controller *c)
 {
-	struct i2o_controller *iop; 
+	struct i2o_controller *iop;
 	u32 m;
 	u8 *status;
 	u32 *msg;
@@ -1002,19 +1470,19 @@
 	for (iop = i2o_controller_chain; iop; iop = iop->next)
 		i2o_quiesce_controller(iop);
 
+	/* Get a message */
 	m=i2o_wait_message(c, "AdapterReset");
 	if(m==0xFFFFFFFF)	
 		return -ETIMEDOUT;
 	msg=(u32 *)(c->mem_offset+m);
-
-	status = kmalloc(4,GFP_KERNEL);
-	if (status==NULL) {
-		printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
-			c->name);
+	
+	status=(void *)kmalloc(4, GFP_KERNEL);
+	if(status==NULL) {
+		printk(KERN_ERR "IOP reset failed - no free memory.\n");
 		return -ENOMEM;
 	}
-	memset(status,0,4);
-
+	memset(status, 0, 4);
+	
 	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
 	msg[2]=core_context;
@@ -1028,11 +1496,11 @@
 
 	/* Wait for a reply */
 	time=jiffies;
-	while (status[0]==0)
+	while(status[0]==0)
 	{
-		if((jiffies-time)>=5*HZ)
+		if((jiffies-time)>=20*HZ)
 		{
-			printk(KERN_ERR "%s: IOP reset timeout.\n", c->name);
+			printk(KERN_ERR "IOP reset timeout.\n");
 			kfree(status);
 			return -ETIMEDOUT;
 		}
@@ -1040,26 +1508,27 @@
 		barrier();
 	}
 
-	if (status[0]==0x01) 
-	{
+	if (status[0]==0x01)
+	{ 
 		/* 
 		 * Once the reset is sent, the IOP goes into the INIT state 
 		 * which is indeterminate.  We need to wait until the IOP 
 		 * has rebooted before we can let the system talk to 
 		 * it. We read the inbound Free_List until a message is 
-		 * available.  If we can't read one in the given amount of 
+		 * available.  If we can't read one in the given ammount of 
 		 * time, we assume the IOP could not reboot properly.  
 		 */ 
 
+		dprintk(KERN_INFO "Reset succeeded...waiting for reboot\n"); 
+
 		time = jiffies; 
 		m = I2O_POST_READ32(c); 
 		while(m == 0XFFFFFFFF) 
 		{ 
 			if((jiffies-time) >= 30*HZ)
 			{
-				printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n",
+				printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", 
 						c->name); 
-				kfree(status);
 				return -ETIMEDOUT; 
 			} 
 			schedule(); 
@@ -1069,7 +1538,7 @@
 
 		i2o_flush_reply(c,m);
 
-		dprintk((KERN_INFO "%s: Reset completed.\n", c->name));
+		dprintk(KERN_INFO "%s: Reset completed.\n", c->name);
 	}
 
 	/* If IopReset was rejected or didn't perform reset, try IopClear */
@@ -1077,22 +1546,24 @@
 	i2o_status_get(c);
 	if (status[0] == 0x02 || c->status_block->iop_state != ADAPTER_STATE_RESET)
 	{
-		printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); 
+		printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name);
 		i2o_clear_controller(c);
-
 	}
 
 	/* Enable other IOPs */
 
 	for (iop = i2o_controller_chain; iop; iop = iop->next)
 		if (iop != c)
-			i2o_enable_controller(iop);		
+			i2o_enable_controller(iop);
 
 	kfree(status);
 	return 0;
 }
 
 
+/*
+ * Get the status block for the IOP
+ */
 int i2o_status_get(struct i2o_controller *c)
 {
 	long time;
@@ -1100,23 +1571,25 @@
 	u32 *msg;
 	u8 *status_block;
 
-	if (c->status_block == NULL) {
+	if (c->status_block == NULL) 
+	{
 		c->status_block = (i2o_status_block *)
-					kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
+			kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
 		if (c->status_block == NULL)
 		{
-			printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", c->name);
+			printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n",
+				c->name);
 			return -ENOMEM;
 		}
 	}
 
 	status_block = (u8*)c->status_block;
 	memset(c->status_block,0,sizeof(i2o_status_block));
-
+	
 	m=i2o_wait_message(c, "StatusGet");
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
-
+	
 	msg=(u32 *)(c->mem_offset+m);
 
 	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
@@ -1126,13 +1599,13 @@
 	msg[4]=0;
 	msg[5]=0;
 	msg[6]=virt_to_phys(c->status_block);
-	msg[7]=0;	/* 64bit host FIXME */
+	msg[7]=0;   /* 64bit host FIXME */
 	msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
 
 	i2o_post_message(c,m);
 
 	/* Wait for a reply */
-	
+
 	time=jiffies;
 	while(status_block[87]!=0xFF)
 	{
@@ -1144,43 +1617,47 @@
 		schedule();
 		barrier();
 	}
-	
+
 	/* Ok the reply has arrived. Fill in the important stuff */
-	c->inbound_size = c->status_block->inbound_frame_size *4;
+	c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
 
 #ifdef DRIVERDEBUG
 	printk(KERN_INFO "%s: State = ", c->name);
 	switch (c->status_block->iop_state) {
-		case 0x01:	
-			printk("INIT\n"); 
+		case 0x01:  
+			printk("INIT\n");
 			break;
-		case 0x02:	
-			printk("RESET\n"); 
+		case 0x02:
+			printk("RESET\n");
 			break;
-		case 0x04:	
-			printk("HOLD\n"); 
+		case 0x04:
+			printk("HOLD\n");
 			break;
-		case 0x05:	
-			printk("READY\n"); 
+		case 0x05:
+			printk("READY\n");
 			break;
-		case 0x08:	
-			printk("OPERATIONAL\n"); 
+		case 0x08:
+			printk("OPERATIONAL\n");
 			break;
-		case 0x10:	
-			printk("FAILED\n"); 
+		case 0x10:
+			printk("FAILED\n");
 			break;
-		case 0x11:	
-			printk("FAULTED\n"); 
+		case 0x11:
+			printk("FAULTED\n");
 			break;
-		default:	
+		default: 
 			printk("%x (unknown !!)\n",c->status_block->iop_state);
-	}
-#endif
+}     
+#endif   
 
 	return 0;
 }
 
-
+/*
+ * Get the Hardware Resource Table for the device.
+ * The HRT contains information about possible hidden devices
+ * but is mostly useless to us 
+ */
 int i2o_hrt_get(struct i2o_controller *c)
 {
 	u32 msg[6];
@@ -1199,7 +1676,6 @@
 
 		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
 		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
-		/* msg[2] filled in i2o_post_wait */
 		msg[3]= 0;
 		msg[4]= (0xD0000000 | size);	/* Simple transaction */
 		msg[5]= virt_to_phys(c->hrt);	/* Dump it here */
@@ -1222,51 +1698,49 @@
 	return 0;
 }
 
+/*
+ * Send the I2O System Table to the specified IOP
+ *
+ * The system table contains information about all the IOPs in the
+ * system.  It is build and then sent to each IOP so that IOPs can
+ * establish connections between each other.
+ *
+ */
 static int i2o_systab_send(struct i2o_controller *iop)
 {
-        u32 msg[12];
-        u32 privmem[2];
-        u32 privio[2];
-        int ret;
-
-	/* See i2o_status_block */
-#if 0
-        iop->status->current_mem_base;
-        iop->status->current_mem_size;
-        iop->status->current_io_base;
-        iop->status->current_io_size;
-#endif
+	u32 msg[12];
+	u32 privmem[2];
+	u32 privio[2];
+	int ret;
 
-/* FIXME */
-        privmem[0]=iop->priv_mem;       /* Private memory space base address */
-        privmem[1]=iop->priv_mem_size;
-        privio[0]=iop->priv_io;         /* Private I/O address */
-        privio[1]=iop->priv_io_size;
+	privmem[0] = iop->status_block->current_mem_base;
+	privmem[1] = iop->status_block->current_mem_size;
+	privio[0] = iop->status_block->current_io_base;
+	privio[1] = iop->status_block->current_io_size;
 
 	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
-        msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
-	/* msg[2] filled in i2o_post_wait */
+	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
 	msg[3] = 0;
-        msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
-        msg[5] = 0;                               /* Segment 0 */
+	msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+	msg[5] = 0;                               /* Segment 0 */
 
-        /* 
-         * Provide three SGL-elements:
-         * System table (SysTab), Private memory space declaration and 
-         * Private i/o space declaration  
-	 */
-        msg[6] = 0x54000000 | sys_tbl_len;
-        msg[7] = virt_to_phys(sys_tbl);
-        msg[8] = 0x54000000 | 0;
-        msg[9] = virt_to_phys(privmem);
-        msg[10] = 0xD4000000 | 0;
-        msg[11] = virt_to_phys(privio);
+	/* 
+ 	 * Provide three SGL-elements:
+ 	 * System table (SysTab), Private memory space declaration and 
+ 	 * Private i/o space declaration  
+ 	 */
+	msg[6] = 0x54000000 | sys_tbl_len;
+	msg[7] = virt_to_phys(sys_tbl);
+	msg[8] = 0x54000000 | 0;
+	msg[9] = virt_to_phys(privmem);
+	msg[10] = 0xD4000000 | 0;
+	msg[11] = virt_to_phys(privio);
 
 	if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
 		printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", 
 			iop->name, ret);
 	else
-		dprintk((KERN_INFO "%s: SysTab set.\n", iop->name));
+		dprintk(KERN_INFO "%s: SysTab set.\n", iop->name);
 
 	return ret;	
 
@@ -1281,10 +1755,11 @@
 
 	printk(KERN_INFO "Activating I2O controllers\n");
 	printk(KERN_INFO "This may take a few minutes if there are many devices\n");
-
+	
 	/* In INIT state, Activate IOPs */
-
 	for (iop = i2o_controller_chain; iop; iop = niop) {
+		dprintk(KERN_INFO "Calling i2o_activate_controller for %s\n", 
+			iop->name);
 		niop = iop->next;
 		i2o_activate_controller(iop);
 	}
@@ -1299,6 +1774,7 @@
 	 * If build_sys_table fails, we kill everything and bail
 	 * as we can't init the IOPs w/o a system table
 	 */	
+	dprintk(KERN_INFO "calling i2o_build_sys_table\n");
 	if (i2o_build_sys_table() < 0) {
 		i2o_sys_shutdown();
 		return;
@@ -1307,11 +1783,30 @@
 	/* If IOP don't get online, we need to rebuild the System table */
 	for (iop = i2o_controller_chain; iop; iop = niop) {
 		niop = iop->next;
+		dprintk(KERN_INFO "Calling i2o_online_controller for %s\n", iop->name);
 		if (i2o_online_controller(iop) < 0)
 			goto rebuild_sys_tab;
 	}
 	
 	/* Active IOPs now in OPERATIONAL state */
+
+	/*
+	 * Register for status updates from all IOPs
+	 */
+	for(iop = i2o_controller_chain; iop; iop=iop->next) {
+
+		/* Create a kernel thread to deal with dynamic LCT updates */
+		iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND);
+	
+		/* Update change ind on DLCT */
+		iop->dlct->change_ind = iop->lct->change_ind;
+
+		/* Start dynamic LCT updates */
+		i2o_lct_notify(iop);
+
+		/* Register for all events from IRTOS */
+		i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF);
+	}
 }
 
 /*
@@ -1335,14 +1830,14 @@
  */
 int i2o_activate_controller(struct i2o_controller *iop)
 {
-	/* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */
+	/* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
 	/* In READY state, Get status */
 
 	if (i2o_status_get(iop) < 0) {
-		printk("Unable to obtain status of IOP, attempting a reset.\n");
+		printk(KERN_INFO "Unable to obtain status of IOP, attempting a reset.\n");
 		i2o_reset_controller(iop);
 		if (i2o_status_get(iop) < 0) {
-			printk("IOP not responding.\n");
+			printk(KERN_ERR "%s: IOP not responding.\n", iop->name);
 			i2o_delete_controller(iop);
 			return -1;
 		}
@@ -1354,13 +1849,18 @@
 		return -1;
 	}
 
-//	if (iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
 	if (iop->status_block->iop_state == ADAPTER_STATE_READY ||
 	    iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+	    iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
 	    iop->status_block->iop_state == ADAPTER_STATE_FAILED)
 	{
-		dprintk((KERN_INFO "%s: already running...trying to reset\n",
-				iop->name));
+		u32 m[MSG_FRAME_SIZE];
+		dprintk(KERN_INFO "%s: already running...trying to reset\n",
+			iop->name);
+
+		i2o_init_outbound_q(iop);
+		I2O_REPLY_WRITE32(iop,virt_to_phys(m));
+
 		i2o_reset_controller(iop);			
 
 		if (i2o_status_get(iop) < 0 || 
@@ -1377,6 +1877,9 @@
 		return -1;
 	}
 
+	if (i2o_post_outbound_messages(iop)) 
+		return -1;
+
 	/* In HOLD state */
 	
 	if (i2o_hrt_get(iop) < 0) {
@@ -1387,6 +1890,7 @@
 	return 0;
 }
 
+
 /*
  * Clear and (re)initialize IOP's outbound queue
  */
@@ -1396,8 +1900,8 @@
 	u32 m;
 	u32 *msg;
 	u32 time;
-	int i;
 
+	dprintk(KERN_INFO "%s: Initializing Outbound Queue\n", c->name);
 	m=i2o_wait_message(c, "OutboundInit");
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
@@ -1410,66 +1914,72 @@
 		return -ENOMEM;
 	}
 	memset(status, 0, 4);
-	
-	msg[0]= EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6;
+
+
+	msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
 	msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
 	msg[2]= core_context;
-	msg[3]= 0x0106;			/* Transaction context */
-	msg[4]= 4096;			/* Host page frame size */
+	msg[3]= 0x0106;						/* Transaction context */
+	msg[4]= 4096;							/* Host page frame size */
 	/* Frame size is in words. Pick 128, its what everyone elses uses and
-	   other sizes break some adapters. */
-	msg[5]= (MSG_FRAME_SIZE>>2)<<16|0x80;	/* Outbound msg frame size and Initcode */
-	msg[6]= 0xD0000004;		/* Simple SG LE, EOB */
+		other sizes break some adapters. */
+	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size and Initcode */
+	msg[6]= 0xD0000004;					/* Simple SG LE, EOB */
 	msg[7]= virt_to_bus(status);
 
 	i2o_post_message(c,m);
 	
-	barrier();	
+	barrier();
 	time=jiffies;
 	while(status[0]<0x02)
 	{
-		if((jiffies-time)>=5*HZ)
+		if((jiffies-time)>=30*HZ)
 		{
 			if(status[0]==0x00)
 				printk(KERN_ERR "%s: Ignored queue initialize request.\n",
 					c->name);
-			else
+			else  
 				printk(KERN_ERR "%s: Outbound queue initialize timeout.\n",
 					c->name);
 			kfree(status);
 			return -ETIMEDOUT;
-		}
+		}  
 		schedule();
 		barrier();
-	}
+	}  
 
 	if(status[0] != I2O_CMD_OUTBOUND_INIT_COMPLETE)
 	{
-		printk(KERN_ERR "%s: Outbound queue initialize rejected (%d).\n",
-			c->name, status[0]);
+		printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name);
 		kfree(status);
-		return -EINVAL;
+		return -ETIMEDOUT;
 	}
+
+	return 0;
+}
+
+int i2o_post_outbound_messages(struct i2o_controller *c)
+{
+	int i;
+	u32 m;
 	/* Alloc space for IOP's outbound queue message frames */
 
 	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
 	if(c->page_frame==NULL) {
 		printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
 			c->name);
-		kfree(status);
 		return -ENOMEM;
-	}	
+	}
 	m=virt_to_phys(c->page_frame);
-	
+
 	/* Post frames */
 
 	for(i=0; i< NMBR_MSG_FRAMES; i++) {
-  		I2O_REPLY_WRITE32(c,m);
-                mb();
+		I2O_REPLY_WRITE32(c,m);
+		mb();
 		m += MSG_FRAME_SIZE;
 	}
 
-	kfree(status);
 	return 0;
 }
 
@@ -1520,11 +2030,31 @@
 	return 0;
 }
 
+/*
+ * Like above, but used for async notification.  The main
+ * difference is that we keep track of the CurrentChangeIndiicator
+ * so that we only get updates when it actually changes.
+ *
+ */
+int i2o_lct_notify(struct i2o_controller *c)
+{
+	u32 msg[8];
+
+	msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+	msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2] = core_context;
+	msg[3] = 0xDEADBEEF;	
+	msg[4] = 0xFFFFFFFF;	/* All devices */
+	msg[5] = c->dlct->change_ind+1;	/* Next change */
+	msg[6] = 0xD0000000|8192;
+	msg[7] = virt_to_bus(c->dlct);
 
+	return i2o_post_this(c, msg, sizeof(msg));
+}
+		
 /*
  *	Bring a controller online into OPERATIONAL state. 
  */
- 
 int i2o_online_controller(struct i2o_controller *iop)
 {
 	if (i2o_systab_send(iop) < 0) {
@@ -1534,6 +2064,7 @@
 
 	/* In READY state */
 
+	dprintk(KERN_INFO "Attempting to enable iop%d\n", iop->unit);
 	if (i2o_enable_controller(iop) < 0) {
 		i2o_delete_controller(iop);
 		return -1;
@@ -1541,6 +2072,7 @@
 
 	/* In OPERATIONAL state  */
 
+	dprintk(KERN_INFO "Attempting to get/parse lct iop%d\n", iop->unit);
 	if (i2o_lct_get(iop) < 0){
 		i2o_delete_controller(iop);
 		return -1;
@@ -1549,9 +2081,18 @@
 	return 0;
 }
 
+/*
+ * Build system table
+ *
+ * The system table contains information about all the IOPs in the
+ * system (duh) and is used by the Executives on the IOPs to establish
+ * peer2peer connections.  We're not supporting peer2peer at the moment,
+ * but this will be needed down the road for things like lan2lan forwarding.
+ */
 static int i2o_build_sys_table(void)
 {
 	struct i2o_controller *iop = NULL;
+	struct i2o_controller *niop = NULL;
 	int count = 0;
 
 	sys_tbl_len = sizeof(struct i2o_sys_tbl) +	// Header + IOPs
@@ -1563,7 +2104,7 @@
 
 	sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);
 	if(!sys_tbl) {
-		printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");	
+		printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");
 		return -ENOMEM;
 	}
 	memset((void*)sys_tbl, 0, sys_tbl_len);
@@ -1572,12 +2113,23 @@
 	sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */
 	sys_tbl->change_ind = sys_tbl_ind++;
 
-	for(iop = i2o_controller_chain; iop; iop = iop->next)
+	for(iop = i2o_controller_chain; iop; iop = niop)
 	{
-		// Get updated Status Block so we have the latest information
-		if (i2o_status_get(iop)) {
+		niop = iop->next;
+
+		/* 
+		 * Get updated IOP state so we have the latest information
+		 *
+		 * We should delete the controller at this point if it
+		 * doesn't respond since  if it's not on the system table 
+		 * it is techninically not part of the I2O subsyßtem...
+		 */
+		if(i2o_status_get(iop)) {
+			printk(KERN_ERR "%s: Deleting b/c could not get status while"
+				"attempting to build system table", iop->name);
+			i2o_delete_controller(iop);		
 			sys_tbl->num_entries--;
-			continue; // try next one	
+			continue; // try the next one
 		}
 
 		sys_tbl->iops[count].org_id = iop->status_block->org_id;
@@ -1603,10 +2155,10 @@
 
 #ifdef DRIVERDEBUG
 {
-	u32 *table = (u32*)sys_tbl;
+	u32 *table;
+	table = (u32*)sys_tbl;
 	for(count = 0; count < (sys_tbl_len >>2); count++)
-		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", 
-			count, table[count]);
+		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);
 }
 #endif
 
@@ -1641,18 +2193,19 @@
 	if(m==0xFFFFFFFF)
 	{
 		printk(KERN_ERR "%s: Timeout waiting for message frame!\n",
-				c->name);
+		       c->name);
 		return -ETIMEDOUT;
 	}
-
 	msg = (u32 *)(c->mem_offset + m);
-	memcpy_toio(msg, data, len);
+ 	memcpy_toio(msg, data, len);
 	i2o_post_message(c,m);
 	return 0;
 }
 
 /*
- *	Post a message and wait for a response flag to be set.
+ * This core API allows an OSM to post a message and then be told whether
+ * or not the system received a successful reply.  It is useful when
+ * the OSM does not want to know the exact 3
  */
 int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
 {
@@ -1677,15 +2230,28 @@
 	spin_unlock_irqrestore(&post_wait_lock, flags);
 
 	wait_data->wq = &wq_i2o_post;
-	wait_data->status = -EAGAIN;
-
-	msg[2]=0x80000000|(u32)core_context|((u32)wait_data->id<<16);
+	wait_data->status = -ETIMEDOUT;
 
+	msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16);
+	
 	if ((status = i2o_post_this(c, msg, len))==0) {
 		interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
 		status = wait_data->status;
-	}
+	}  
+
+#ifdef DRIVERDEBUG
+	if(status == -ETIMEDOUT)
+		printk(KERN_INFO "POST WAIT TIMEOUT\n");
+#endif
 
+	/* 
+	 * Remove the entry from the queue.
+	 * Since i2o_post_wait() may have been called again by
+	 * a different thread while we were waiting for this 
+	 * instance to complete, we're not guaranteed that 
+	 * this entry is at the head of the queue anymore, so 
+	 * we need to search for it, find it, and delete it.
+	 */
 	p2 = NULL;
 	spin_lock_irqsave(&post_wait_lock, flags);
 	for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) {
@@ -1694,6 +2260,7 @@
 				p2->next = p1->next;
 			else
 				post_wait_queue = p1->next;
+
 			break;
 		}
 	}
@@ -1710,7 +2277,7 @@
  */
 static void i2o_post_wait_complete(u32 context, int status)
 {
-	struct i2o_post_wait_data *p1;
+	struct i2o_post_wait_data *p1 = NULL;
 
 	/* 
 	 * We need to search through the post_wait 
@@ -1728,60 +2295,21 @@
 	for(p1 = post_wait_queue; p1; p1 = p1->next) {
 		if(p1->id == ((context >> 16) & 0x7fff)) {
 			p1->status = status;
-			spin_unlock(&post_wait_lock);
 			wake_up_interruptible(p1->wq);
+			spin_unlock(&post_wait_lock);
 			return;
 		}
 	}
 	spin_unlock(&post_wait_lock);
 
-	printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!");
-}
-
-/*
- *      Send UTIL_EVENT messages
- */
-
-int i2o_event_register(struct i2o_controller *c, int tid, int context,
-                        u32 evt_mask)
-{
-        u32 msg[5];
-
-        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-        msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid;
-        msg[2] = context;
-        msg[3] = 0;
-        msg[4] = evt_mask;
-
-        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
-                return -ETIMEDOUT;
-
-        return 0;
-}
-
-int i2o_event_ack(struct i2o_controller *c, int tid, int context,
-                u32 evt_indicator, void *evt_data, int evt_data_len)
-{
-        u32 msg[c->inbound_size];
-
-        msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5;
-        msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid;
-	msg[2] = context;
-	msg[3] = 0;
-        msg[4] = evt_indicator;
-        memcpy(msg+5, evt_data, evt_data_len);
-
-        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
-                return -ETIMEDOUT;
-
-        return 0;
+	printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n");
 }
 
 /*
  *	Issue UTIL_CLAIM or UTIL_RELEASE messages
  */
- 
-static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, u32 type)
+static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, 
+				int onoff, u32 type)
 {
 	u32 msg[5];
 
@@ -1791,53 +2319,71 @@
 	else	
 		msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid;
 
-	/* msg[2] filled in i2o_post_wait */	
 	msg[3] = 0;
 	msg[4] = type;
-
-	return i2o_post_wait(c, msg, sizeof(msg), 2);
+	
+	return i2o_post_wait(c, msg, sizeof(msg), 30);
 }
 
 /*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
  *
  *	This function can be used for all UtilParamsGet/Set operations.
- *	The OperationBlock is given in opblk-buffer, 
- *	and results are returned in resblk-buffer.
- *	Note that the minimum sized resblk is 8 bytes and contains
+ *	The OperationList is given in oplist-buffer, 
+ *	and results are returned in reslist-buffer.
+ *	Note that the minimum sized reslist is 8 bytes and contains
  *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
  */
 int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, 
-                void *opblk, int oplen, void *resblk, int reslen)
+                void *oplist, int oplen, void *reslist, int reslen)
 {
 	u32 msg[9]; 
-	u32 *res = (u32 *)resblk;
+	u8 *res = (u8 *)reslist;
+	u32 *res32 = (u32*)reslist;
+	u32 *restmp = (u32*)reslist;
+	int len = 0;
+	int i = 0;
 	int wait_status;
 
 	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
 	msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
-	/* msg[2] filled in i2o_post_wait */
 	msg[3] = 0;
 	msg[4] = 0;
-	msg[5] = 0x54000000 | oplen;	/* OperationBlock */
-	msg[6] = virt_to_bus(opblk);
-	msg[7] = 0xD0000000 | reslen;	/* ResultBlock */
-	msg[8] = virt_to_bus(resblk);
-
-	if ((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 20)))
-   		return wait_status; 	/* -DetailedStatus */
-
-	if (res[1]&0x00FF0000) 	/* BlockStatus != SUCCESS */
-	{
-		printk(KERN_WARNING "%s: %s - Error:\n  ErrorInfoSize = 0x%02x, "
-			"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
-			iop->name,
-			(cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
-							 : "PARAMS_GET",   
-			res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
-		return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+	msg[5] = 0x54000000 | oplen;	/* OperationList */
+	msg[6] = virt_to_bus(oplist);
+	msg[7] = 0xD0000000 | reslen;	/* ResultList */
+	msg[8] = virt_to_bus(reslist);
+
+	if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10)))
+   	return wait_status; 	/* -DetailedStatus */
+
+	/*
+	 * Calculate number of bytes of Result LIST
+	 * We need to loop through each Result BLOCK and grab the length
+	 */
+	restmp = res32 + 1;
+	len = 1;
+	for(i = 0; i < (res32[0]&0X0000FFFF); i++)
+	{
+		if(restmp[0]&0x00FF0000)	/* BlockStatus != SUCCESS */
+		{
+			printk(KERN_WARNING "%s - Error:\n  ErrorInfoSize = 0x%02x, " 
+					"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+					(cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+					: "PARAMS_GET",   
+					res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF);
+	
+			/*
+			 *	If this is the only request,than we return an error
+			 */
+			if((res32[0]&0x0000FFFF) == 1)
+				return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+		}
+
+		len += restmp[0] & 0x0000FFFF;	/* Length of res BLOCK */
+		restmp += restmp[0] & 0x0000FFFF;	/* Skip to next BLOCK */
 	}
 
-        return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ 
+	return (len << 2);  /* bytes used by result list */
 }
 
 /*
@@ -1852,15 +2398,15 @@
 
 	if (field == -1)  		/* whole group */
        		opblk[4] = -1;
-
+              
 	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, 
 		opblk, sizeof(opblk), resblk, sizeof(resblk));
-			
+		
 	if (size < 0)
 		return size;	
 
 	memcpy(buf, resblk+8, buflen);  /* cut off header */
-	return buflen;
+	return buflen < size ? buflen : size;
 }
 
 /*
@@ -1904,22 +2450,17 @@
 }
 
 /* 
- * 	if oper == I2O_PARAMS_TABLE_GET: 
- *		Get all table group fields from all rows or
- *		get specific table group fields from all rows.
- *
- * 		if fieldcount == -1 we query all fields from all rows
- *			ibuf is NULL and ibuflen is 0
- * 		else we query specific fields from all rows
+ * 	if oper == I2O_PARAMS_TABLE_GET, get from all rows 
+ * 		if fieldcount == -1 return all fields
+ *			ibuf and ibuflen are unused (use NULL, 0)
+ * 		else return specific fields
  *  			ibuf contains fieldindexes
  *
- * 	if oper == I2O_PARAMS_LIST_GET:
- *		Get all table group fields from specified rows or
- *		get specific table group fields from specified rows.
- *
- * 		if fieldcount == -1 we query all fields from specified rows
+ * 	if oper == I2O_PARAMS_LIST_GET, gte form specific rows
+ * 		if fieldcount == -1 return all fields
  *			ibuf contains rowcount, keyvalues
- * 		else we query specific fields from specified rows
+ * 		else return specific fields
+ *			fieldcount is # of fieldindexes
  *  			ibuf contains fieldindexes, rowcount, keyvalues
  *
  *	You could also use directly function i2o_issue_params().
@@ -1955,7 +2496,6 @@
 /*
  * 	Clear table group, i.e. delete all rows.
  */
-
 int i2o_clear_table(struct i2o_controller *iop, int tid, int group)
 {
 	u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group };
@@ -1973,7 +2513,6 @@
  * 	else just specific fields are given, rest use defaults
  *  		buf contains fieldindexes, rowcount, keyvalues
  */	
-
 int i2o_row_add_table(struct i2o_controller *iop, int tid,
 		    int group, int fieldcount, void *buf, int buflen)
 {
@@ -2005,7 +2544,6 @@
 /*
  *	Delete rows from a table group.
  */ 
-
 int i2o_row_delete_table(struct i2o_controller *iop, int tid,
 		    int group, int keycount, void *keys, int keyslen)
 {
@@ -2034,6 +2572,9 @@
 	return size;
 }
 
+/*
+ * Used for error reporting/debugging purposes
+ */
 void i2o_report_common_status(u8 req_status)
 {
 	/* the following reply status strings are common to all classes */
@@ -2061,6 +2602,9 @@
 	return;
 }
 
+/*
+ * Used for error reporting/debugging purposes
+ */
 static void i2o_report_common_dsc(u16 detailed_status)
 {
 	/* The following detailed statuscodes are valid 
@@ -2108,6 +2652,9 @@
 	return;
 }
 
+/*
+ * Used for error reporting/debugging purposes
+ */
 static void i2o_report_lan_dsc(u16 detailed_status)
 {
 	static char *LAN_DSC[] = {	// Lan detailed status code strings
@@ -2140,6 +2687,9 @@
 	return;	
 }
 
+/*
+ * Used for error reporting/debugging purposes
+ */
 static void i2o_report_util_cmd(u8 cmd)
 {
 	switch (cmd) {
@@ -2192,7 +2742,9 @@
 	return;	
 }
 
-
+/*
+ * Used for error reporting/debugging purposes
+ */
 static void i2o_report_exec_cmd(u8 cmd)
 {
 	switch (cmd) {
@@ -2302,6 +2854,9 @@
 	return;	
 }
 
+/*
+ * Used for error reporting/debugging purposes
+ */
 static void i2o_report_lan_cmd(u8 cmd)
 {
 	switch (cmd) {
@@ -2327,38 +2882,45 @@
 	return;
 }
 
-/* TODO: Add support for other classes */
+/*
+ * Used for error reporting/debugging purposes
+ */
 void i2o_report_status(const char *severity, const char *module, u32 *msg)
 {
 	u8 cmd = (msg[1]>>24)&0xFF;
 	u8 req_status = (msg[4]>>24)&0xFF;
 	u16 detailed_status = msg[4]&0xFFFF;
+	struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)];
 
 	printk("%s%s: ", severity, module);
 
-	if (cmd < 0x1F) { 			// Utility Class
-		i2o_report_util_cmd(cmd);
-		i2o_report_common_status(req_status);
-		i2o_report_common_dsc(detailed_status);
-		return;
-	}
+	switch (h->class) {	
+		case I2O_CLASS_EXECUTIVE:
+			if (cmd < 0x1F) { 		// Utility cmd
+				i2o_report_util_cmd(cmd);
+				i2o_report_common_status(req_status);
+				i2o_report_common_dsc(detailed_status);
+			}
+			if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive cmd
+				i2o_report_exec_cmd(cmd);
+				i2o_report_common_status(req_status);
+				i2o_report_common_dsc(detailed_status);
+			}
+		break;
 
-	if (cmd >= 0x30 && cmd <= 0x3F) {	// LAN class
-		i2o_report_lan_cmd(cmd);
-		i2o_report_common_status(req_status);		
-		i2o_report_lan_dsc(detailed_status);
-		return;
-	}
-	
-	if (cmd >= 0xA0 && cmd <= 0xEF) {	// Executive class
-		i2o_report_exec_cmd(cmd);
-		i2o_report_common_status(req_status);
-		i2o_report_common_dsc(detailed_status);
-		return;
+		case I2O_CLASS_LAN:
+			i2o_report_lan_cmd(cmd);
+			i2o_report_common_status(req_status);		
+			i2o_report_lan_dsc(detailed_status);
+		break;
+/*
+    		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+    		break;
+*/  	
+		default:	
+			printk(KERN_INFO "%02x, %02x / %04x.\n", 
+				cmd, req_status, detailed_status);
 	}
-	
-	printk("%02x, %02x / %04x.\n", cmd, req_status, detailed_status);
-	return;
 }
 
 /* Used to dump a message to syslog during debugging */
@@ -2366,7 +2928,6 @@
 {
 #ifdef DRIVERDEBUG
 	int i;
-
 	printk(KERN_INFO "Dumping I2O message size %d @ %p\n", 
 		msg[0]>>16&0xffff, msg);
 	for(i = 0; i < ((msg[0]>>16)&0xffff); i++)
@@ -2374,53 +2935,102 @@
 #endif
 }
 
-#ifdef MODULE
+/*
+ * I2O reboot/shutdown notification.
+ *
+ * - Call each OSM's reboot notifier (if one exists)
+ * - Quiesce each IOP in the system
+ *
+ * Each IOP has to be quiesced before we can ensure that the system
+ * can be properly shutdown as a transaction that has already been
+ * acknowledged still needs to be placed in permanent store on the IOP.
+ * The SysQuiesce causes the IOP to force all HDMs to complete their
+ * transactions before returning, so only at that point is it safe
+ * 
+ */
+static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void
+*p)
+{
+	int i = 0;
+	struct i2o_controller *c = NULL;
 
-EXPORT_SYMBOL(i2o_install_handler);
-EXPORT_SYMBOL(i2o_remove_handler);
+	if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
+		return NOTIFY_DONE;
 
-EXPORT_SYMBOL(i2o_install_controller);
-EXPORT_SYMBOL(i2o_delete_controller);
-EXPORT_SYMBOL(i2o_unlock_controller);
-EXPORT_SYMBOL(i2o_find_controller);
+	printk(KERN_INFO "Shutting down I2O system.\n");
+	printk(KERN_INFO 
+		"   This could take a few minutes if there are many devices attached\n");
+
+	for(i = 0; i < MAX_I2O_MODULES; i++)
+	{
+		if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify)
+			i2o_handlers[i]->reboot_notify();
+	}
+
+	for(c = i2o_controller_chain; c; c = c->next)
+	{
+		if(i2o_quiesce_controller(c))
+		{
+			printk(KERN_WARNING "i2o: Could not quiesce %s."  "
+				Verify setup on next system power up.\n", c->name);
+		}
+	}
+
+	printk(KERN_INFO "I2O system down.\n");
+	return NOTIFY_DONE;
+}
+
+
+#ifdef MODULE
+
+EXPORT_SYMBOL(i2o_controller_chain);
 EXPORT_SYMBOL(i2o_num_controllers);
+EXPORT_SYMBOL(i2o_find_controller);
+EXPORT_SYMBOL(i2o_unlock_controller);
+EXPORT_SYMBOL(i2o_status_get);
 
-EXPORT_SYMBOL(i2o_event_register);
-EXPORT_SYMBOL(i2o_event_ack);
+EXPORT_SYMBOL(i2o_install_handler);
+EXPORT_SYMBOL(i2o_remove_handler);
 
 EXPORT_SYMBOL(i2o_claim_device);
 EXPORT_SYMBOL(i2o_release_device);
-EXPORT_SYMBOL(i2o_run_queue);
-EXPORT_SYMBOL(i2o_activate_controller);
-EXPORT_SYMBOL(i2o_get_class_name);
-EXPORT_SYMBOL(i2o_status_get);
+EXPORT_SYMBOL(i2o_device_notify_on);
+EXPORT_SYMBOL(i2o_device_notify_off);
+
+EXPORT_SYMBOL(i2o_post_this);
+EXPORT_SYMBOL(i2o_post_wait);
 
 EXPORT_SYMBOL(i2o_query_scalar);
 EXPORT_SYMBOL(i2o_set_scalar);
 EXPORT_SYMBOL(i2o_query_table);
 EXPORT_SYMBOL(i2o_clear_table);
 EXPORT_SYMBOL(i2o_row_add_table);
-
-EXPORT_SYMBOL(i2o_post_this);
-EXPORT_SYMBOL(i2o_post_wait);
+EXPORT_SYMBOL(i2o_row_delete_table);
 EXPORT_SYMBOL(i2o_issue_params);
 
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_event_ack);
+
 EXPORT_SYMBOL(i2o_report_status);
+EXPORT_SYMBOL(i2o_dump_message);
+EXPORT_SYMBOL(i2o_get_class_name);
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
 
+
 int init_module(void)
 {
-	printk(KERN_INFO "I2O Core - (c) Copyright 1999 Red Hat Software.\n");
+	printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
 	if (i2o_install_handler(&i2o_core_handler) < 0)
 	{
 		printk(KERN_ERR 
-			"i2o: Unable to install core handler.\nI2O stack not loaded!");
+			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
 		return 0;
 	}
 
 	core_context = i2o_core_handler.context;
+
 	/*
 	 * Attach core to I2O PCI transport (and others as they are developed)
 	 */
@@ -2429,22 +3039,61 @@
 		printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
 #endif
 
+	/*
+	 * Initialize event handling thread
+	 */	
+	init_MUTEX_LOCKED(&evt_sem);
+	evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND);
+	if(evt_pid < 0)
+	{
+		printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
+		i2o_remove_handler(&i2o_core_handler);
+		return 0;
+	}
+	else
+		printk(KERN_INFO "event thread created as pid %d\n", evt_pid);
+
 	if(i2o_num_controllers)
 		i2o_sys_init();
 
+	register_reboot_notifier(&i2o_reboot_notifier);
+
 	return 0;
 }
 
 void cleanup_module(void)
 {
+	int stat;
+
+	unregister_reboot_notifier(&i2o_reboot_notifier);
+
 	if(i2o_num_controllers)
 		i2o_sys_shutdown();
 
+	/*
+	 * If this is shutdown time, the thread has already been killed
+	 */
+	if(evt_running) {
+		stat = kill_proc(evt_pid, SIGTERM, 1);
+		if(!stat) {
+			int count = 10 * 100;
+			while(evt_running && count) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+	
+			if(!count)
+				printk(KERN_ERR "i2o: Event thread still running!\n");
+		}
+	}
+
 #ifdef CONFIG_I2O_PCI_MODULE
 	i2o_pci_core_detach();
 #endif
 
 	i2o_remove_handler(&i2o_core_handler);
+
+	unregister_reboot_notifier(&i2o_reboot_notifier);
 }
 
 #else
@@ -2468,12 +3117,29 @@
 
 	core_context = i2o_core_handler.context;
 
+	/*
+	 * Initialize event handling thread
+	 * We may not find any controllers, but still want this as 
+	 * down the road we may have hot pluggable controllers that
+	 * need to be dealt with.
+	 */	
+	init_MUTEX_LOCKED(&evt_sem);
+	if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0)
+	{
+		printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
+		i2o_remove_handler(&i2o_core_handler);
+		return 0;
+	}
+
+
 #ifdef CONFIG_I2O_PCI
 	i2o_pci_init();
 #endif
 
 	if(i2o_num_controllers)
 		i2o_sys_init();
+
+	register_reboot_notifier(&i2o_reboot_notifier);
 
 	i2o_config_init();
 #ifdef CONFIG_I2O_BLOCK
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.3.99-pre5/linux/drivers/i2o/i2o_lan.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/i2o/i2o_lan.c	Wed Apr 12 09:38:53 2000
@@ -1,10 +1,10 @@
 /*
- *	linux/drivers/i2o/i2o_lan.c
+ *	drivers/i2o/i2o_lan.c
  *
- * 	I2O LAN CLASS OSM 	January 7th 1999
+ * 	I2O LAN CLASS OSM 		April 3rd 2000
  *
- *	(C) Copyright 1999 	University of Helsinki,
- *				Department of Computer Science
+ *	(C) Copyright 1999, 2000 	University of Helsinki,
+ *		      			Department of Computer Science
  *
  * 	This code is still under development / test.
  *
@@ -14,7 +14,8 @@
  *	2 of the License, or (at your option) any later version.
  *
  *	Authors: 	Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *	Fixes:		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *	 		Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
  *			Deepak Saxena <deepak@plexity.net>
  *
  *	Tested:		in FDDI environment (using SysKonnect's DDM)
@@ -31,10 +32,12 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/fddidevice.h>
+#include <linux/trdevice.h>
+#include <linux/fcdevice.h>
+
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/malloc.h>
-#include <linux/trdevice.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/tqueue.h>
@@ -52,46 +55,62 @@
 #define dprintk(s, args...)
 #endif
 
-/* Module params */
-
-static u32 bucketpost   = I2O_BUCKET_COUNT;
-static u32 bucketthresh = I2O_BUCKET_THRESH;
-static u32 rx_copybreak = 200;
+/* The following module parameters are used as default values
+ * for per interface values located in the net_device private area.
+ * Private values are changed via /proc filesystem.
+ */
+static u32 max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;
+static u32 bucket_thresh   = I2O_LAN_BUCKET_THRESH;
+static u32 rx_copybreak    = I2O_LAN_RX_COPYBREAK;
+static tx_batch_mode	   = I2O_LAN_TX_BATCH_MODE;
+static i2o_event_mask      = I2O_LAN_EVENT_MASK;
 
 #define MAX_LAN_CARDS 16
 static struct net_device *i2o_landevs[MAX_LAN_CARDS+1];
-static int unit = -1; 			/* device unit number */
+static int unit = -1; 	  /* device unit number */
 
-struct i2o_lan_local {
-	u8 unit;
-	struct i2o_device *i2o_dev;
-	struct fddi_statistics stats;   /* see also struct net_device_stats */
-	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
-	u32 bucket_count;  		/* nbr of buckets sent to DDM */
-	u32 tx_count; 	  		/* packets in one TX message frame */
-	u32 tx_max_out;	   		/* DDM's Tx queue len */
-	u32 tx_out;			/* outstanding TXes */
-	u32 sgl_max;			/* max SGLs in one message frame */
-	u32 m;				/* IOP address of msg frame */
-
-	struct tq_struct i2o_batch_send_task;
-	struct sk_buff **i2o_fbl;	/* Free bucket list (to reuse skbs) */
-	int i2o_fbl_tail;
+extern rwlock_t dev_mc_lock;
 
-	spinlock_t lock;
-};
-
-static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
-                          struct i2o_message *m);
-static void i2o_lan_event_reply(struct net_device *dev, u32 *msg);
+static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);			 
+static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
 static int i2o_lan_receive_post(struct net_device *dev);
-static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg);
+static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);
 static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg);
 
+static int i2o_lan_reset(struct net_device *dev);
+static void i2o_lan_handle_event(struct net_device *dev, u32 *msg);
+
+/* Structures to register handlers for the incoming replies. */
+
+static struct i2o_handler i2o_lan_send_handler = {
+	i2o_lan_send_post_reply, 	// For send replies
+	NULL,
+	NULL,
+	NULL,
+	"I2O Lan OSM send",
+	-1,
+	I2O_CLASS_LAN
+};
+static int lan_send_context;
+
+static struct i2o_handler i2o_lan_receive_handler = {
+	i2o_lan_receive_post_reply,	// For receive replies
+	NULL,
+	NULL,
+	NULL,
+	"I2O Lan OSM receive",
+	-1,
+	I2O_CLASS_LAN
+};
+static int lan_receive_context;
+
 static struct i2o_handler i2o_lan_handler = {
-	i2o_lan_reply,
+	i2o_lan_reply,			// For other replies
+	NULL,
+	NULL,
+	NULL,
 	"I2O Lan OSM",
-	0,              // context
+	-1,
 	I2O_CLASS_LAN
 };
 static int lan_context;
@@ -100,245 +119,264 @@
 	0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0
 };
 
+/* Functions to handle message failures and transaction errors:
+==============================================================*/
+
 /*
- * i2o_lan_reply(): The only callback function to handle incoming messages.
+ * i2o_lan_handle_failure(): Fail bit has been set since IOP's message
+ * layer cannot deliver the request to the target, or the target cannot
+ * process the request.
  */
-static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
-			  struct i2o_message *m)
+static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg)
 {
-	u32 *msg = (u32 *)m;
-	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
-	struct net_device *dev = i2o_landevs[unit];
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
 
-    	if (msg[0] & (1<<13)) { // Fail bit is set
- 		printk(KERN_ERR "%s: IOP failed to process the msg:\n",dev->name);
-		printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid = %d\n",
-			(msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
-		printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n  "
-			"LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
-			 msg[4] >> 24, (msg[4] >> 16) & 0xFF,
-			(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
-		printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
-			msg[5] >> 16, msg[5] & 0xFFF);
-		return;
-	}	
+	u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]);
+	// FIXME on 64-bit host
+	u32 *sgl_elem = &preserved_msg[4];
+	struct sk_buff *skb = NULL;
+	u8 le_flag;
+
+// To be added to i2o_core.c
+//	i2o_report_failure(KERN_INFO, iop, dev->name, msg);
+
+	/* If PacketSend failed, free sk_buffs reserved by upper layers */
+
+	if (msg[1] >> 24 == LAN_PACKET_SEND) {
+		do {
+			skb = (struct sk_buff *)(sgl_elem[1]);
+			dev_kfree_skb_irq(skb);
+
+			atomic_dec(&priv->tx_out);
+
+			le_flag = *sgl_elem >> 31;
+			sgl_elem +=3;
+		} while (le_flag == 0); /* Last element flag not set */
 
-#ifndef DRIVERDEBUG
-	if (msg[4] >> 24)  	/* ReqStatus != SUCCESS */
-#endif
-		i2o_report_status(KERN_INFO, dev->name, msg);
-	
-	switch (msg[1] >> 24) {
-	case LAN_RECEIVE_POST:
-	{
-		if (netif_running(dev)) {
-			if (!(msg[4]>>24)) {
-				i2o_lan_receive_post_reply(dev,msg);
-				break;
-			}
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+	}
 
-			// Something VERY wrong if this is happening
-			printk( KERN_WARNING "%s: rejected bucket post.\n", dev->name);
-		}
+	/* If ReceivePost failed, free sk_buffs we have reserved */
 
-		// Shutting down, we are getting unused buckets back
-		i2o_lan_release_buckets(dev,msg);	
-	
-		break;
+	if (msg[1] >> 24 == LAN_RECEIVE_POST) {
+		do {
+			skb = (struct sk_buff *)(sgl_elem[1]);
+			dev_kfree_skb_irq(skb);
+
+			atomic_dec(&priv->buckets_out);
+
+			le_flag = *sgl_elem >> 31;
+			sgl_elem +=3;
+		} while (le_flag == 0); /* Last element flag not set */
 	}
 
-	case LAN_PACKET_SEND:
-	case LAN_SDU_SEND:
-	{
-		struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-		u8 trl_count  = msg[3] & 0x000000FF;
+	/* Release the preserved msg frame by resubmitting it as a NOP */
 
-		while (trl_count) {
-			// The HDM has handled the outgoing packet
-			dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]);
-			dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
-				dev->name,trl_count);
-			priv->tx_out--;
-			trl_count--;
-		}
+	preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+	preserved_msg[2] = 0;
+	i2o_post_message(iop, msg[7]);
+}
+/*
+ * i2o_lan_handle_transaction_error(): IOP or DDM has rejected the request
+ * for general cause (format error, bad function code, insufficient resources,
+ * etc.). We get one transaction_error for each failed transaction.
+ */
+static void i2o_lan_handle_transaction_error(struct net_device *dev, u32 *msg)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct sk_buff *skb;
+
+// To be added to i2o_core.c
+//	i2o_report_transaction_error(KERN_INFO, dev->name, msg);
+
+	/* If PacketSend was rejected, free sk_buff reserved by upper layers */
+
+	if (msg[1] >> 24 == LAN_PACKET_SEND) {
+		skb = (struct sk_buff *)(msg[3]); // TransactionContext
+		dev_kfree_skb_irq(skb);
+		atomic_dec(&priv->tx_out);
 
 		if (netif_queue_stopped(dev))
 			netif_wake_queue(dev);
-	
-		break;	
-	}
-
-	case LAN_RESET: 	/* default reply without payload */
-	case LAN_SUSPEND:
-		break;
+ 	}
 
-	case I2O_CMD_UTIL_EVT_REGISTER:
-        case I2O_CMD_UTIL_EVT_ACK:
-        	i2o_lan_event_reply(dev, msg);
-        	break;
+	/* If ReceivePost was rejected, free sk_buff we have reserved */
 
-	default:
-		printk(KERN_ERR "%s: No handler for the reply.\n", dev->name);
-		i2o_report_status(KERN_INFO, dev->name, msg);		
+	if (msg[1] >> 24 == LAN_RECEIVE_POST) {
+		skb = (struct sk_buff *)(msg[3]);
+		dev_kfree_skb_irq(skb);
+		atomic_dec(&priv->buckets_out);
 	}
 }
 
 /*
- * i2o_lan_event_reply(): Handle events.
+ * i2o_lan_handle_status(): Common parts of handling a not succeeded request
+ * (status != SUCCESS).
  */
-static void i2o_lan_event_reply(struct net_device *dev, u32 *msg)
+static int i2o_lan_handle_status(struct net_device *dev, u32 *msg)
 {
-        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-        struct i2o_device *i2o_dev = priv->i2o_dev;
-        struct i2o_controller *iop = i2o_dev->controller;
-        struct i2o_reply {
-                u8  version_offset;
-                u8  msg_flags;
-                u16 msg_size;
-                u32 tid:12;
-                u32 initiator:12;
-                u32 function:8;
-                u32 initiator_context;
-                u32 transaction_context;
-                u32 evt_indicator;
-                u32 evt_data[(iop->inbound_size - 20) / 4];     /* max */
-        } *evt = (struct i2o_reply *)msg;
-
-        int evt_data_len = (evt->msg_size - 5) * 4;             /* real */
-
-        if (evt->function == I2O_CMD_UTIL_EVT_REGISTER) {
-                printk(KERN_INFO "%s: I2O event - ", dev->name);
-
-                switch (evt->evt_indicator) {
-                        case I2O_EVT_IND_STATE_CHANGE:
-                                printk("State chance 0x%08X.\n",
-                                        evt->evt_data[0]);
-                                break;
-                        case I2O_EVT_IND_GENERAL_WARNING:
-                                printk("General warning 0x%02X.\n",
-                                        evt->evt_data[0]);
-                                break;
-                        case I2O_EVT_IND_CONFIGURATION_FLAG:
-                                printk("Configuration requested.\n");
-                                break;
-                        case I2O_EVT_IND_LOCK_RELEASE:
-                                printk("Lock released.\n");
-                                break;
-                        case I2O_EVT_IND_CAPABILITY_CHANGE:
-                                printk("Capability change 0x%02X.\n",
-                                        evt->evt_data[0]);
-                                break;
-                        case I2O_EVT_IND_DEVICE_RESET:
-                                printk("Device reset.\n");
-                                break;
-                        case I2O_EVT_IND_EVT_MASK_MODIFIED:
-                                printk("Event mask modified, 0x%08X.\n",
-                                        evt->evt_data[0]);
-                                break;
-                        case I2O_EVT_IND_FIELD_MODIFIED: {
-                                u16 *work16 = (u16 *)evt->evt_data;
-                                printk("Group 0x%04X, field %d changed.\n",
-                                        work16[0], work16[1]);
-                                break;
-                        }
-                        case I2O_EVT_IND_VENDOR_EVT: {
-                                int i;
-                                printk("Vendor event:\n");
-                                for (i = 0; i < evt_data_len / 4; i++)
-                                        printk("   0x%08X\n", evt->evt_data[i]);
-                                break;
-                        }
-                        case I2O_EVT_IND_DEVICE_STATE:
-                                printk("Device state changed 0x%08X.\n",
-                                        evt->evt_data[0]);
-                                break;
-                        case I2O_LAN_EVT_LINK_DOWN:
-                                printk("Link to the physical device is lost.\n");
-                                break;
-                        case I2O_LAN_EVT_LINK_UP:
-                                printk("Link to the physical device is (re)established.\n");
-                                break;
-                        case I2O_LAN_EVT_MEDIA_CHANGE:
-                                printk("Media change.\n");
-                                break;
-                        default:
-                                printk("Event Indicator = 0x%08X.\n",
-                                        evt->evt_indicator);
-                }
-
-                /*
-                 * EventAck necessary only for events that cause the device
-                 * to syncronize with the user
-                 *
-                 *if (i2o_event_ack(iop, i2o_dev->lct_data->tid,
-                 *               priv->unit << 16 | lan_context,
-                 *               evt->evt_indicator,
-                 *               evt->evt_data, evt_data_len) < 0)
-                 *       printk("%s: Event Acknowledge timeout.\n", dev->name);
-                 */
-        }
+	/* Fail bit set? */
+
+	if (msg[0] & MSG_FAIL) {
+		i2o_lan_handle_failure(dev, msg);
+		return -1;
+	}
+
+	/* Message rejected for general cause? */
+
+	if ((msg[4]>>24) == I2O_REPLY_STATUS_TRANSACTION_ERROR) {
+		i2o_lan_handle_transaction_error(dev, msg);
+		return -1;
+	}
 
-        /* else evt->function == I2O_CMD_UTIL_EVT_ACK) */
-        /* Do we need to do something here too? */
+	/* Else have to handle it in the callback function */
+
+	return 0;
 }
 
+/* Callback functions called from the interrupt routine:
+=======================================================*/
+
 /*
- * i2o_lan_release_buckets(): Handle unused buckets.
+ * i2o_lan_send_post_reply(): Callback function to handle PostSend replies.
  */
-static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
+static void i2o_lan_send_post_reply(struct i2o_handler *h,
+			struct i2o_controller *iop, struct i2o_message *m)
 {
-        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-	u8 trl_count  = (u8)(msg[3] & 0x000000FF);
-	u32 *pskb = &msg[6];
+	u32 *msg = (u32 *)m;
+	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
+	struct net_device *dev = i2o_landevs[unit];
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	u8 trl_count  = msg[3] & 0x000000FF;
 
-	while (trl_count--) {
-		dprintk("%s: Releasing unused sk_buff %p.\n",dev->name,
-			(struct sk_buff*)(*pskb));
-		dev_kfree_skb((struct sk_buff*)(*pskb));
-		pskb++;
-		priv->bucket_count--;
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
+	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
+		if (i2o_lan_handle_status(dev, msg))
+			return;
+
+		/* Else we get pending transmit request(s) back */
+	}
+
+	/* DDM has handled transmit request(s), free sk_buffs */
+
+	while (trl_count) {
+		dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]);
+		dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
+			dev->name, trl_count);
+		atomic_dec(&priv->tx_out);
+		trl_count--;
 	}
+
+	/* If priv->tx_out had reached tx_max_out, the queue was stopped */
+
+	if (netif_queue_stopped(dev))
+ 		netif_wake_queue(dev);
 }
 
 /*
- * i2o_lan_receive_post_reply(): Process incoming packets.
+ * i2o_lan_receive_post_reply(): Callback function to process incoming packets.
  */
-static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
+static void i2o_lan_receive_post_reply(struct i2o_handler *h,
+				       struct i2o_controller *iop, struct i2o_message *m)
 {
+	u32 *msg = (u32 *)m;
+	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
+	struct net_device *dev = i2o_landevs[unit];
+
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6];
 	struct i2o_packet_info *packet;
 	u8 trl_count = msg[3] & 0x000000FF;
 	struct sk_buff *skb, *old_skb;
+	unsigned long flags = 0;
+
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
+	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
+		if (i2o_lan_handle_status(dev, msg))
+			return;
+
+		/* Getting unused buckets back? */
+
+		if (msg[4] & I2O_LAN_DSC_CANCELED ||
+		    msg[4] & I2O_LAN_DSC_RECEIVE_ABORTED) {
+			i2o_lan_release_buckets(dev, msg);
+			return;
+		}
+
+		/* Which DetailedStatusCodes need special treatment? */
+	}
+
+	/* Else we are receiving incoming post. */
 
 	while (trl_count--) {
-		skb = (struct sk_buff *)bucket->context;		
-		packet = (struct i2o_packet_info *)bucket->packet_info;	
-		priv->bucket_count--;
+		skb = (struct sk_buff *)bucket->context;
+		packet = (struct i2o_packet_info *)bucket->packet_info;
+		atomic_dec(&priv->buckets_out);
+#if 0
+/* Is this enough? If we get erroneous bucket, we can't assume that skb could
+ * be reused, can we?
+ */
+
+		/* Should we optimise these ifs away from the fast path? -taneli */
+		if (packet->flags & 0x0f) {
+
+			if (packet->flags & 0x01)
+				printk(KERN_WARNING "%s: packet with errors.\n", dev->name);
+			if (packet->flags & 0x0c)
+				/* This actually means that the hw is b0rken, since we
+				   have asked it to not send fragmented packets. */
+				printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", dev->name);
+			bucket++;
+			if (skb)
+				dev_kfree_skb_irq(skb);
+			continue;
+		}
 
-		if (packet->len < rx_copybreak) {
+		if (packet->status & 0xff) {
+			/* Silently discard, unless debugging. */
+			dprintk(KERN_DEBUG "%s: toasted packet received.\n", dev->name);
+			bucket++;
+			if (skb)
+				dev_kfree_skb_irq(skb);
+			continue;
+		}
+#endif
+		if (packet->len < priv->rx_copybreak) {
 			old_skb = skb;
-			skb = (struct sk_buff *)dev_alloc_skb(packet->len+2);	
+			skb = (struct sk_buff *)dev_alloc_skb(packet->len+2);
 			if (skb == NULL) {
-				printk("%s: Can't allocate skb.\n", dev->name);
-				return -ENOMEM;
-			}				
-			skb_reserve(skb,2);
-			memcpy(skb_put(skb,packet->len), old_skb->data, packet->len);
+				printk(KERN_ERR "%s: Can't allocate skb.\n", dev->name);
+				return;
+			}
+			skb_reserve(skb, 2);
+			memcpy(skb_put(skb, packet->len), old_skb->data, packet->len);
 
-			if (priv->i2o_fbl_tail < I2O_BUCKET_COUNT)
-				priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb;	
+			spin_lock_irqsave(&priv->fbl_lock, flags);
+			if (priv->i2o_fbl_tail < I2O_LAN_MAX_BUCKETS_OUT)
+				priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb;
 			else
-				dev_kfree_skb(old_skb);
+				dev_kfree_skb_irq(old_skb);
+			spin_unlock_irqrestore(&priv->fbl_lock, flags);
 		} else
-			skb_put(skb,packet->len);	
-	
+			skb_put(skb, packet->len);
+
 		skb->dev = dev;
 		skb->protocol = priv->type_trans(skb, dev);
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 
 		dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered "
-			"to upper level.\n",dev->name,packet->len);
+			"to upper level.\n", dev->name, packet->len);
 
 		bucket++; // to next Packet Descriptor Block
 	}
@@ -346,19 +384,193 @@
 #ifdef DRIVERDEBUG
 	if (msg[5] == 0)
 		printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n",
-			 dev->name, priv->bucket_count);
+		       dev->name, atomic_read(&priv->buckets_out));
 #endif
 
-        if (priv->bucket_count <= bucketpost - bucketthresh) {
-        	i2o_post_buckets_task.data = (void *)dev;
-        	queue_task(&i2o_post_buckets_task, &tq_immediate);
- 		mark_bh(IMMEDIATE_BH);
-		/* Note: the task is queued only once */
+	/* If DDM has already consumed bucket_tresh buckets, post new ones */
+
+	if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) {
+		i2o_post_buckets_task.data = (void *)dev;
+		queue_task(&i2o_post_buckets_task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+
+	return;
+}
+
+/*
+ * i2o_lan_reply(): Callback function to handle other incoming messages
+ * except SendPost and ReceivePost.
+ */
+static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
+			  struct i2o_message *m)
+{
+	u32 *msg = (u32 *)m;
+	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
+	struct net_device *dev = i2o_landevs[unit];
+
+#ifdef DRIVERDEBUG
+	i2o_report_status(KERN_INFO, dev->name, msg);
+#endif
+
+	if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) {
+		if (i2o_lan_handle_status(dev, msg))
+			return;
+
+		/* This should NOT be reached */
+	}
+
+	switch (msg[1] >> 24) {
+	case LAN_RESET:
+	case LAN_SUSPEND:
+		/* default reply without payload */
+		break;
+	case I2O_CMD_UTIL_EVT_REGISTER:
+	case I2O_CMD_UTIL_EVT_ACK:
+		i2o_lan_handle_event(dev, msg);
+		break;
+	default:
+		printk(KERN_ERR "%s: No handler for the reply.\n",
+		       dev->name);
+		i2o_report_status(KERN_INFO, dev->name, msg);
+	}
+}
+
+/* Functions used by the above callback functions:
+=================================================*/
+/*
+ * i2o_lan_release_buckets(): Free unused buckets (sk_buffs).
+ */
+static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	u8 trl_elem_size = (u8)(msg[3]>>8 & 0x000000FF);
+	u8 trl_count = (u8)(msg[3] & 0x000000FF);
+	u32 *pskb = &msg[6];
+
+	while (trl_count--) {
+		dprintk(KERN_DEBUG "%s: Releasing unused sk_buff %p (trl_count=%d).\n",
+			dev->name, (struct sk_buff*)(*pskb),trl_count+1);
+		dev_kfree_skb_irq((struct sk_buff *)(*pskb));
+		pskb += 1 + trl_elem_size;
+		atomic_dec(&priv->buckets_out);
 	}
-                        	
-	return 0;
 }
 
+/*
+ * i2o_lan_event_reply(): Handle events.
+ */
+static void i2o_lan_handle_event(struct net_device *dev, u32 *msg)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	struct i2o_reply {
+		u8  version_offset;
+		u8  msg_flags;
+		u16 msg_size;
+		u32 tid:12;
+		u32 initiator:12;
+		u32 function:8;
+		u32 initiator_context;
+		u32 transaction_context;
+		u32 evt_indicator;
+		u32 data[(iop->inbound_size - 20) / 4];	/* max */
+	} *evt = (struct i2o_reply *)msg;
+	int evt_data_len = (evt->msg_size - 5) * 4;	/* real */
+
+	printk(KERN_INFO "%s: I2O event - ", dev->name);
+
+	if (evt->function == I2O_CMD_UTIL_EVT_ACK) {
+		printk("Event acknowledgement reply.\n");
+		return;
+	}
+
+	/* Else evt->function == I2O_CMD_UTIL_EVT_REGISTER) */
+
+	switch (evt->evt_indicator) {
+	case I2O_EVT_IND_STATE_CHANGE:  {
+		struct state_data {
+			u16 status;
+			u8 state;
+			u8 data;
+		} *evt_data = (struct state_data *)(evt->data[0]);
+
+		printk("State chance 0x%08x.\n", evt->data[0]);
+
+		/* If the DDM is in error state, recovery may be
+		 * possible if status = Transmit or Receive Control
+		 * Unit Inoperable.
+		 */
+		if (evt_data->state==0x05 && evt_data->status==0x0003)
+			i2o_lan_reset(dev);
+		break;
+	}
+
+	case I2O_EVT_IND_GENERAL_WARNING:
+		printk("General warning 0x%04x.\n", evt->data[0]);
+		break;
+
+	case I2O_EVT_IND_CONFIGURATION_FLAG:
+		printk("Configuration requested.\n");
+		break;
+
+	case I2O_EVT_IND_CAPABILITY_CHANGE:
+		printk("Capability change 0x%04x.\n", evt->data[0]);
+		break;
+
+	case I2O_EVT_IND_DEVICE_RESET:
+		/* Spec 2.0 p. 6-121:
+		 * The event of _DEVICE_RESET should also be responded
+		 */
+		printk("Device reset.\n");
+		if (i2o_event_ack(iop, msg) < 0)
+			printk("%s: Event Acknowledge timeout.\n", dev->name);
+		break;
+
+	case I2O_EVT_IND_EVT_MASK_MODIFIED:
+		printk("Event mask modified, 0x%08x.\n", evt->data[0]);
+		break;
+
+	case I2O_EVT_IND_FIELD_MODIFIED: {
+		u16 *work16 = (u16 *)evt->data;
+		printk("Group 0x%04x, field %d changed.\n", work16[0],
+		       work16[1]);
+		break;
+	}
+
+	case I2O_EVT_IND_VENDOR_EVT: {
+		int i;
+		printk("Vendor event:\n");
+		for (i = 0; i < evt_data_len / 4; i++)
+			printk("   0x%08x\n", evt->data[i]);
+		break;
+	}
+
+	case I2O_EVT_IND_DEVICE_STATE:
+		printk("Device state changed 0x%08x.\n", evt->data[0]);
+		break;
+
+	case I2O_LAN_EVT_LINK_DOWN:
+		printk("Link to the physical device is lost.\n");
+		break;
+
+	case I2O_LAN_EVT_LINK_UP:
+		printk("Link to the physical device is (re)established.\n");
+		break;
+
+	case I2O_LAN_EVT_MEDIA_CHANGE:
+		printk("Media change.\n");
+		break;
+
+	default:
+		printk("Event Indicator = 0x%08x.\n", evt->evt_indicator);
+	}
+
+	/* Note: EventAck necessary only for events that cause the device to
+	 * syncronize with the user.
+	 */
+}
 
 /*
  * i2o_lan_receive_post(): Post buckets to receive packets.
@@ -369,93 +581,108 @@
 	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;
 	struct sk_buff *skb;
-        u32 m; u32 *msg;
-        u32 bucket_len = (dev->mtu + dev->hard_header_len);
-        u32 total = bucketpost - priv->bucket_count;
-        u32 bucket_count;
-        u32 *sgl_elem;
-
-        while (total) {
-                m = I2O_POST_READ32(iop);
-                if (m == 0xFFFFFFFF)
-                        return -ETIMEDOUT;
-                msg = (u32 *)(iop->mem_offset + m);
-
-                bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total;
-                total -= bucket_count;
-                priv->bucket_count += bucket_count;
+	u32 m, *msg;
+	u32 bucket_len = (dev->mtu + dev->hard_header_len);
+	u32 total = priv->max_buckets_out - atomic_read(&priv->buckets_out);
+	u32 bucket_count;
+	u32 *sgl_elem;
+	unsigned long flags;
+
+	/* Send (total/bucket_count) separate I2O requests */
+
+	while (total) {
+		m = I2O_POST_READ32(iop);
+		if (m == 0xFFFFFFFF)
+			return -ETIMEDOUT;
+		msg = (u32 *)(iop->mem_offset + m);
+
+		bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total;
+		total -= bucket_count;
+		atomic_add(bucket_count, &priv->buckets_out);
 
-                dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n",
-                        dev->name, bucket_count, bucket_len);
+		dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN DDM.\n",
+			dev->name, bucket_count, bucket_len);
+
+		/* Fill in the header */
 
 		__raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg);
-		__raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1);
-		__raw_writel(priv->unit << 16 | lan_context, msg+2);
+		__raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
+		__raw_writel(priv->unit << 16 | lan_receive_context, msg+2);
 		__raw_writel(bucket_count, msg+3);
-                sgl_elem = &msg[4];
+		sgl_elem = &msg[4];
+
+		/* Fill in the payload - contains bucket_count SGL elements */
 
-                while (bucket_count--) {
-                        if (priv->i2o_fbl_tail >= 0)
-                                skb = priv->i2o_fbl[priv->i2o_fbl_tail--];
-                        else {
-                                skb = dev_alloc_skb(bucket_len + 2);
-                                if (skb == NULL)
-                                        return -ENOMEM;
-                                skb_reserve(skb, 2);
-                        }
-                        __raw_writel(0x51000000 | bucket_len, sgl_elem);
-                        __raw_writel((u32)skb,		      sgl_elem+1);
-                        __raw_writel(virt_to_bus(skb->data),  sgl_elem+2);
-                        sgl_elem += 3;
-                }
+		while (bucket_count--) {
+			spin_lock_irqsave(&priv->fbl_lock, flags);
+			if (priv->i2o_fbl_tail >= 0)
+				skb = priv->i2o_fbl[priv->i2o_fbl_tail--];
+			else {
+				skb = dev_alloc_skb(bucket_len + 2);
+				if (skb == NULL) {
+					spin_unlock_irqrestore(&priv->fbl_lock, flags);
+					return -ENOMEM;
+				}
+				skb_reserve(skb, 2);
+			}
+			spin_unlock_irqrestore(&priv->fbl_lock, flags);
 
-		/* set LE flag and post buckets */
+			__raw_writel(0x51000000 | bucket_len, sgl_elem);
+			__raw_writel((u32)skb,		      sgl_elem+1);
+			__raw_writel(virt_to_bus(skb->data),  sgl_elem+2);
+			sgl_elem += 3;
+		}
+
+		/* set LE flag and post  */
 		__raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3));
-                i2o_post_message(iop,m);
-        }
+		i2o_post_message(iop, m);
+	}
 
-        return 0;
+	return 0;
 }
 
+/* Functions called from the network stack, and functions called by them:
+========================================================================*/
+
 /*
  * i2o_lan_reset(): Reset the LAN adapter into the operational state and
  * 	restore it to full operation.
  */
 static int i2o_lan_reset(struct net_device *dev)
 {
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;	
+	struct i2o_controller *iop = i2o_dev->controller;
 	u32 msg[5];
 
 	dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name);
 	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-	msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
+	msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid;
 	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
 	msg[3] = 0; 				 // TransactionContext
-	msg[4] = 1 << 16; 			 // return posted buckets
+	msg[4] = 0;				// keep posted buckets
 
 	if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
-		return -ETIMEDOUT;		
+		return -ETIMEDOUT;
 
 	return 0;
 }
 
 /*
  * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state.
- * 	Reply to any LAN class message with status error_no_data_transfer
+ * 	IOP replies to any LAN class message with status error_no_data_transfer
  *	/ suspended.
  */
 static int i2o_lan_suspend(struct net_device *dev)
 {
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	struct i2o_device *i2o_dev = priv->i2o_dev;
-	struct i2o_controller *iop = i2o_dev->controller;	
+	struct i2o_controller *iop = i2o_dev->controller;
 	u32 msg[5];
 
 	dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name);
 	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
-	msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
+	msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid;
 	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
 	msg[3] = 0; 				 // TransactionContext
 	msg[4] = 1 << 16; 			 // return posted buckets
@@ -471,75 +698,91 @@
  */
 static void i2o_set_batch_mode(struct net_device *dev)
 {
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
-	struct i2o_device *i2o_dev = priv->i2o_dev;	
-	struct i2o_controller *iop = i2o_dev->controller;	
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
 	u32 val;
 
-	/* set LAN_BATCH_CONTROL attributes */
+	/* Set defaults LAN_BATCH_CONTROL attributes */
+	/* May be changed via /proc or Configuration Utility */
 
-	// enable batch mode, toggle automatically
-	val = 0x00000000;
-	if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0003, 0, &val, sizeof(val)) <0)
+	val = 0x00000000; // enable batch mode, toggle automatically
+	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0003, 0, &val, sizeof(val)) <0)
 		printk(KERN_WARNING "%s: Unable to enter I2O LAN batch mode.\n",
-			dev->name);
+		       dev->name);
 	else
-		dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name);
+		dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n", dev->name);
+
+	/* Set LAN_OPERATION attributes */
+
+#ifdef DRIVERDEBUG
+/* Added for testing: this will be removed */
+	val = 0x00000003; 			// 1 = UserFlags
+	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 1, &val, sizeof(val)) < 0)
+		printk(KERN_WARNING "%s: Can't enable ErrorReporting & BadPacketHandling.\n",
+		       dev->name);
+	else
+		dprintk(KERN_INFO "%s: ErrorReporting enabled, "
+			"BadPacketHandling enabled.\n", dev->name);
+#endif /* DRIVERDEBUG */
 
 	/*
 	 * When PacketOrphanlimit is same as the maximum packet length,
 	 * the packets will never be split into two separate buckets
 	 */
-
-	/* set LAN_OPERATION attributes */
-
-	val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit
-	if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0004, 2, &val, sizeof(val)) < 0)
+	val = dev->mtu + dev->hard_header_len; // 2 = PacketOrphanLimit
+	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 2, &val, sizeof(val)) < 0)
 		printk(KERN_WARNING "%s: Unable to set PacketOrphanLimit.\n",
-			dev->name);
+		       dev->name);
 	else
 		dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n",
-			dev->name,val);
-	
-	return;	
+			dev->name, val);
+
+	return;
 }
 
+/* Functions called from the network stack:
+==========================================*/
+
 /*
  * i2o_lan_open(): Open the device to send/receive packets via
- * the network device.	
+ * the network device.
  */
 static int i2o_lan_open(struct net_device *dev)
 {
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	struct i2o_device *i2o_dev = priv->i2o_dev;
-#if 0
 	struct i2o_controller *iop = i2o_dev->controller;
-	u32 evt_mask =  0xFFC00007; // All generic events, all lan events
-#endif
-	if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) {
+
+	MOD_INC_USE_COUNT;
+
+	if (i2o_claim_device(i2o_dev, &i2o_lan_handler)) {
 		printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
+		MOD_DEC_USE_COUNT;
 		return -EAGAIN;
 	}
-	dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n",
-		dev->name, i2o_dev->lct_data->tid);
-#if 0
-	if (i2o_event_register(iop, i2o_dev->lct_data->tid,
-				priv->unit << 16 | lan_context, evt_mask) < 0)
+	dprintk(KERN_INFO "%s: I2O LAN device (tid=%d) claimed by LAN OSM.\n",
+		dev->name, i2o_dev->lct_data.tid);
+
+	if (i2o_event_register(iop, i2o_dev->lct_data.tid,
+			       priv->unit << 16 | lan_context, 0, priv->i2o_event_mask) < 0)
 		printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name);
-#endif
+
 	i2o_lan_reset(dev);
-	
-	priv->i2o_fbl = kmalloc(bucketpost * sizeof(struct sk_buff *),GFP_KERNEL);
-	if (priv->i2o_fbl == NULL)
+
+	priv->i2o_fbl = kmalloc(priv->max_buckets_out * sizeof(struct sk_buff *),
+				GFP_KERNEL);
+	if (priv->i2o_fbl == NULL) {
+		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
+	}
 	priv->i2o_fbl_tail = -1;
-
-	netif_start_queue(dev);
+	priv->send_active = 0;
 
 	i2o_set_batch_mode(dev);
 	i2o_lan_receive_post(dev);
 
-	MOD_INC_USE_COUNT;
+	netif_start_queue(dev);
 
 	return 0;
 }
@@ -549,22 +792,24 @@
  */
 static int i2o_lan_close(struct net_device *dev)
 {
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
-	struct i2o_device *i2o_dev = priv->i2o_dev;	
-#if 0
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;
 
-	if (i2o_event_register(iop, i2o_dev->lct_data->tid,
-				priv->unit << 16 | lan_context, 0) < 0)
-		printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
-#endif				dev->name);
-
 	netif_stop_queue(dev);
+
 	i2o_lan_suspend(dev);
 
-	if (i2o_release_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY))
+	if (i2o_event_register(iop, i2o_dev->lct_data.tid,
+			       priv->unit << 16 | lan_context, 0, 0) < 0)
+		printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
+		       dev->name);
+
+	if (i2o_release_device(i2o_dev, &i2o_lan_handler)) {
 		printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
-		       "(tid=%d).\n", dev->name, i2o_dev->lct_data->tid);
+		       "(tid=%d).\n", dev->name, i2o_dev->lct_data.tid);
+		return -EBUSY;
+	}
 
 	while (priv->i2o_fbl_tail >= 0)
 		dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
@@ -575,28 +820,115 @@
 	return 0;
 }
 
-#if 0
 /*
- * i2o_lan_sdu_send(): Send a packet, MAC header added by the HDM.
- * Must be supported by Fibre Channel, optional for Ethernet/802.3,
- * Token Ring, FDDI
+ * i2o_lan_tx_timeout(): Tx timeout handler.
  */
-static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
-{	
-        return -EINVAL;
+static void i2o_lan_tx_timeout(struct net_device *dev)
+{
+ 	if (!netif_queue_stopped(dev))
+		netif_start_queue(dev);
 }
-#endif
 
+#define batching(x, cond) ( (x)->tx_batch_mode==1 || ((x)->tx_batch_mode==2 && (cond)) )
+
+/*
+ * Batch send packets. Both i2o_lan_sdu_send and i2o_lan_packet_send
+ * use this. I'm still not pleased. If you come up with
+ * something better, please tell me. -taneli
+ */
 static void i2o_lan_batch_send(struct net_device *dev)
-{	
+{
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	struct i2o_controller *iop = priv->i2o_dev->controller;
 
+	spin_lock_irq(&priv->tx_lock);
 	if (priv->tx_count != 0) {
+		dev->trans_start = jiffies;
 		i2o_post_message(iop, priv->m);
- 		dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);	
+		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
 		priv->tx_count = 0;
 	}
+	spin_unlock_irq(&priv->tx_lock);
+
+	priv->send_active = 0;
+}
+
+/*
+ * i2o_lan_sdu_send(): Send a packet, MAC header added by the DDM.
+ * Must be supported by Fibre Channel, optional for Ethernet/802.3,
+ * Token Ring, FDDI
+ */
+
+/*
+ * This is a coarse first approximation. Needs testing. Any takers? -taneli
+ */
+static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
+{
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	int tickssofar = jiffies - dev->trans_start;
+	u32 m, *msg;
+	u32 *sgl_elem;
+
+	spin_lock_irq(&priv->tx_lock);
+
+	priv->tx_count++;
+	atomic_inc(&priv->tx_out);
+
+	if (priv->tx_count == 1) {
+		m = I2O_POST_READ32(iop);
+		if (m == 0xFFFFFFFF) {
+			spin_unlock_irq(&priv->tx_lock);
+			return 1;
+		}
+		msg = (u32 *)(iop->mem_offset + m);
+		priv->m = m;
+
+		__raw_writel(NINE_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
+		__raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
+		__raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext
+		__raw_writel(1 << 3, msg+3); 		 	     // TransmitControlWord
+
+		__raw_writel(0xD7000000 | skb->len, msg+4);  	     // MAC hdr included
+		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
+		__raw_writel(virt_to_bus(skb->data), msg+6);
+		__raw_writel((u32)skb->mac.raw, msg+7);
+		__raw_writel((u32)skb->mac.raw+4, msg+8);
+		if (batching(priv, !tickssofar) && !priv->send_active) {
+			priv->send_active = 1;
+			queue_task(&priv->i2o_batch_send_task, &tq_scheduler);
+		}
+	} else {  /* Add new SGL element to the previous message frame */
+
+		msg = (u32 *)(iop->mem_offset + priv->m);
+		sgl_elem = &msg[priv->tx_count * 5 + 1];
+
+		__raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 5) | 1<<12 | SGL_OFFSET_4, msg);
+		__raw_writel(__raw_readl(sgl_elem-5) & 0x7FFFFFFF, sgl_elem-5); /* clear LE flag */
+		__raw_writel(0xD5000000 | skb->len, sgl_elem);
+		__raw_writel((u32)skb, sgl_elem+1);
+		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+		__raw_writel((u32)(skb->mac.raw), sgl_elem+3);
+		__raw_writel((u32)(skb->mac.raw)+1, sgl_elem+4);
+	}
+
+	/* If tx not in batch mode or frame is full, send immediatelly */
+
+	if (!batching(priv, !tickssofar) || priv->tx_count == priv->sgl_max) {
+		dev->trans_start = jiffies;
+		i2o_post_message(iop, priv->m);
+		dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count);
+		priv->tx_count = 0;
+	}
+
+	/* If DDMs TxMaxPktOut reached, stop queueing layer to send more */
+
+	if (atomic_read(&priv->tx_out) >= priv->tx_max_out)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&priv->tx_lock);
+	return 0;
 }
 
 /*
@@ -610,37 +942,37 @@
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;
+	int tickssofar = jiffies - dev->trans_start;
 	u32 m, *msg;
 	u32 *sgl_elem;
 
+	spin_lock_irq(&priv->tx_lock);
+
 	priv->tx_count++;
-	priv->tx_out++;
+	atomic_inc(&priv->tx_out);
 
 	if (priv->tx_count == 1) {
-		dprintk("%s: New message frame\n", dev->name);
-
 		m = I2O_POST_READ32(iop);
 		if (m == 0xFFFFFFFF) {
-			dev_kfree_skb(skb);
-			return -ETIMEDOUT;
+			spin_unlock_irq(&priv->tx_lock);
+			return 1;
 		}
 		msg = (u32 *)(iop->mem_offset + m);
 		priv->m = m;
 
 		__raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
-		__raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1);
-		__raw_writel(priv->unit << 16 | lan_context, msg+2); // InitiatorContext
-		__raw_writel(1 << 4, msg+3);  			     // TransmitControlWord
+		__raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1);
+		__raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext
+		__raw_writel(1 << 3, msg+3); 		 	     // TransmitControlWord
+
 		__raw_writel(0xD5000000 | skb->len, msg+4);  	     // MAC hdr included
 		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
 		__raw_writel(virt_to_bus(skb->data), msg+6);
-
-        	queue_task(&priv->i2o_batch_send_task, &tq_scheduler);
-
+		if (batching(priv, !tickssofar) && !priv->send_active) {
+			priv->send_active = 1;
+			queue_task(&priv->i2o_batch_send_task, &tq_scheduler);
+		}
 	} else {  /* Add new SGL element to the previous message frame */
-	
-		dprintk("%s: Adding packet %d to msg frame\n", 
-			dev->name, priv->tx_count);
 
 		msg = (u32 *)(iop->mem_offset + priv->m);
 		sgl_elem = &msg[priv->tx_count * 3 + 1];
@@ -650,19 +982,23 @@
 		__raw_writel(0xD5000000 | skb->len, sgl_elem);
 		__raw_writel((u32)skb, sgl_elem+1);
 		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+	}
 
-		if (priv->tx_count == priv->sgl_max) { 	/* frame full, send now */
-			i2o_post_message(iop, priv->m);
- 			dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);	
-			priv->tx_count = 0;
-		}
+	/* If tx not in batch mode or frame is full, send immediatelly */
+
+	if (!batching(priv, !tickssofar) || priv->tx_count == priv->sgl_max) {
+		dev->trans_start = jiffies;
+		i2o_post_message(iop, priv->m);
+		dprintk(KERN_DEBUG"%s: %d packets sent.\n", dev->name, priv->tx_count);
+		priv->tx_count = 0;
 	}
-	
-	/* If HDMs TxMaxPktOut reached, stay busy (don't clean tbusy) */
 
-	if (priv->tx_out >= priv->tx_max_out)
+	/* If DDMs TxMaxPktOut reached, stop queueing layer to send more */
+
+	if (atomic_read(&priv->tx_out) >= priv->tx_max_out)
 		netif_stop_queue(dev);
-	
+
+	spin_unlock_irq(&priv->tx_lock);
 	return 0;
 }
 
@@ -671,65 +1007,64 @@
  */
 static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
 {
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
 	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;
 	u64 val64[16];
 	u64 supported_group[4] = { 0, 0, 0, 0 };
 
-        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64,
-        		     sizeof(val64)) < 0)
-        	printk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name);
+	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0100, -1, val64,
+			     sizeof(val64)) < 0)
+		printk(KERN_INFO "%s: Unable to query LAN_HISTORICAL_STATS.\n", dev->name);
 	else {
-        	dprintk("%s: LAN_HISTORICAL_STATS queried.\n",dev->name);
-        	priv->stats.tx_packets = val64[0];
-        	priv->stats.tx_bytes   = val64[1];
-        	priv->stats.rx_packets = val64[2];
-        	priv->stats.rx_bytes   = val64[3];
-        	priv->stats.tx_errors  = val64[4];
-        	priv->stats.rx_errors  = val64[5];
+		dprintk(KERN_DEBUG "%s: LAN_HISTORICAL_STATS queried.\n", dev->name);
+		priv->stats.tx_packets = val64[0];
+		priv->stats.tx_bytes   = val64[1];
+		priv->stats.rx_packets = val64[2];
+		priv->stats.rx_bytes   = val64[3];
+		priv->stats.tx_errors  = val64[4];
+		priv->stats.rx_errors  = val64[5];
 		priv->stats.rx_dropped = val64[6];
 	}
 
-        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0180, -1,
-        		&supported_group, sizeof(supported_group)) < 0)
-        	printk("%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n",dev->name);
+	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0180, -1,
+			     &supported_group, sizeof(supported_group)) < 0)
+		printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n", dev->name);
 
 	if (supported_group[2]) {
-        	if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0183, -1,
-        	 	val64, sizeof(val64)) < 0)
-        		printk("%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n",dev->name);
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0183, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n", dev->name);
 		else {
-        		dprintk("%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n",dev->name);
-			priv->stats.multicast        = val64[4];
+			dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n", dev->name);
+			priv->stats.multicast	     = val64[4];
 			priv->stats.rx_length_errors = val64[10];
 			priv->stats.rx_crc_errors    = val64[0];
 		}
 	}
 
-	if (i2o_dev->lct_data->sub_class == I2O_LAN_ETHERNET) {
-		u64 supported_stats = 0;		
-
-        	if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0200, -1,
-        			 val64, sizeof(val64)) < 0)
-        		printk("%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n",dev->name);
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) {
+		u64 supported_stats = 0;
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0200, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n", dev->name);
 		else {
-        		dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name);
+			dprintk(KERN_DEBUG "%s: LAN_802_3_HISTORICAL_STATS queried.\n", dev->name);
 	 		priv->stats.transmit_collision = val64[1] + val64[2];
-			priv->stats.rx_frame_errors    = val64[0];		
+			priv->stats.rx_frame_errors    = val64[0];
 			priv->stats.tx_carrier_errors  = val64[6];
 		}
 
-        	if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0280, -1,
-        			 &supported_stats, sizeof(supported_stats)) < 0)
-        		printk("%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name);
-
-        	if (supported_stats != 0) {
-        		if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0281, -1,
-        				 val64, sizeof(val64)) < 0)
-        			printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0280, -1,
+				     &supported_stats, sizeof(supported_stats)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name);
+
+		if (supported_stats != 0) {
+			if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0281, -1,
+					     val64, sizeof(val64)) < 0)
+				printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n", dev->name);
 			else {
-        			dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name);
+				dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n", dev->name);
 				if (supported_stats & 0x1)
 					priv->stats.rx_over_errors = val64[0];
 				if (supported_stats & 0x4)
@@ -739,14 +1074,14 @@
 	}
 
 #ifdef CONFIG_TR
-	if (i2o_dev->lct_data->sub_class == I2O_LAN_TR) {
-        	if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0300, -1,
-        			 val64, sizeof(val64)) < 0)
-        		printk("%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n",dev->name);
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_TR) {
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0300, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n", dev->name);
 		else {
 			struct tr_statistics *stats =
-					(struct tr_statistics *)&priv->stats;
-			dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
+				(struct tr_statistics *)&priv->stats;
+			dprintk(KERN_DEBUG "%s: LAN_802_5_HISTORICAL_STATS queried.\n", dev->name);
 
 			stats->line_errors		= val64[0];
 			stats->internal_errors		= val64[7];
@@ -764,25 +1099,29 @@
 #endif
 
 #ifdef CONFIG_FDDI
-	if (i2o_dev->lct_data->sub_class == I2O_LAN_FDDI) {
-        	if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0400, -1,
-        			 val64, sizeof(val64)) < 0)
-        		printk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name);
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_FDDI) {
+		if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0400, -1,
+				     val64, sizeof(val64)) < 0)
+			printk(KERN_INFO "%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n", dev->name);
 		else {
-			dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name);
+			dprintk(KERN_DEBUG "%s: LAN_FDDI_HISTORICAL_STATS queried.\n", dev->name);
 			priv->stats.smt_cf_state = val64[0];
 			memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN);
-			memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN);			
+			memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN);
 			priv->stats.mac_error_cts = val64[3];
 			priv->stats.mac_lost_cts  = val64[4];
 			priv->stats.mac_rmt_state = val64[5];
 			memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8);
-			memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8);	
+			memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8);
 			memcpy(priv->stats.port_lem_cts, &val64[8], 8);
 			memcpy(priv->stats.port_pcm_state, &val64[9], 8);
 		}
 		/* FDDI optional stats not yet defined */
-	}		
+	}
+#endif
+
+#ifdef CONFIG_NET_FC
+	/* Fibre Channel Statistics not yet defined in 1.53 nor 2.0 */
 #endif
 
 	return (struct net_device_stats *)&priv->stats;
@@ -795,70 +1134,79 @@
 
 static void i2o_lan_set_mc_list(struct net_device *dev)
 {
-        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
-        struct i2o_device *i2o_dev = priv->i2o_dev;
-        struct i2o_controller *iop = i2o_dev->controller;
-        u32 filter_mask;
-        u32 max_size_mc_table;
-        u32 mc_addr_group[64];
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	struct i2o_controller *iop = i2o_dev->controller;
+	u32 filter_mask;
+	u32 max_size_mc_table;
+	u32 mc_addr_group[64];
+
+// This isn't safe yet. Needs to be async.
+return;
+
+//	read_lock_bh(&dev_mc_lock);
+//	spin_lock(&dev->xmit_lock);
+//	dev->xmit_lock_owner = smp_processor_id();
 
-        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0001, -1,
-                             &mc_addr_group, sizeof(mc_addr_group)) < 0 ) {
+	if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1,
+			     &mc_addr_group, sizeof(mc_addr_group)) < 0 ) {
 		printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
-                return;
-        }
-
-        max_size_mc_table = mc_addr_group[8];
+		return;
+	}
 
-        if (dev->flags & IFF_PROMISC) {
-                filter_mask = 0x00000002;
-                dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name);
-        }
-
-        else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > max_size_mc_table) {
-                filter_mask = 0x00000004;
-                dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name);
-        }
+	max_size_mc_table = mc_addr_group[8];
 
-        else if (dev->mc_count) {
-                struct dev_mc_list *mc;
+	if (dev->flags & IFF_PROMISC) {
+		filter_mask = 0x00000002;
+		printk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name);
+	} else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > max_size_mc_table) {
+		filter_mask = 0x00000004;
+		printk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name);
+	} else if (dev->mc_count) {
+		struct dev_mc_list *mc;
 		u8 mc_table[2 + 8 * dev->mc_count]; // RowCount, Addresses
 		u64 *work64 = (u64 *)(mc_table + 2);
 
-                filter_mask = 0x00000000;
-                dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name);
+		filter_mask = 0x00000000;
+		printk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name);
 
-                /* Fill multicast addr table */
+		/* Fill multicast addr table */
 
 		memset(mc_table, 0, sizeof(mc_table));
-                memcpy(mc_table, &dev->mc_count, 2);
-                for (mc = dev->mc_list; mc ; mc = mc->next, work64++ )
-                        memcpy(work64, mc->dmi_addr, mc->dmi_addrlen);
-		
+		memcpy(mc_table, &dev->mc_count, 2);
+		for (mc = dev->mc_list; mc ; mc = mc->next, work64++ )
+			memcpy(work64, mc->dmi_addr, mc->dmi_addrlen);
+
 		/* Clear old mc table, copy new table to <iop,tid> */
 
-                if (i2o_clear_table(iop, i2o_dev->lct_data->tid,  0x0002) < 0)
-                        printk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
+		if (i2o_clear_table(iop, i2o_dev->lct_data.tid, 0x0002) < 0)
+			printk(KERN_INFO "%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n", dev->name);
 
-                if ((i2o_row_add_table(iop, i2o_dev->lct_data->tid,  0x0002, -1,
-                        mc_table, sizeof(mc_table))) < 0)
-                        printk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
-        }
-
-        else {	
-                filter_mask = 0x00000300; // Broadcast, Multicast disabled
-                printk(KERN_INFO "%s: Enabling unicast mode...\n",dev->name);
-        }
+		if ((i2o_row_add_table(iop, i2o_dev->lct_data.tid, 0x0002, -1,
+			mc_table, sizeof(mc_table))) < 0)
+			printk(KERN_INFO "%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n", dev->name);
+	} else {
+		filter_mask = 0x00000300; // Broadcast, Multicast disabled
+		printk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name);
+	}
 
 	/* Finally copy new FilterMask to <iop,tid> */
 
-        if (i2o_set_scalar(iop, i2o_dev->lct_data->tid,  0x0001, 3,
-                        &filter_mask, sizeof(filter_mask)) <0)
-                printk(KERN_WARNING "%s: Unable to set MAC FilterMask.\n",dev->name);
+	if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0001, 3,
+			   &filter_mask, sizeof(filter_mask)) <0)
+		printk(KERN_WARNING "%s: Unable to set MAC FilterMask.\n", dev->name);
+
+	dev->xmit_lock_owner = -1;
+	spin_unlock(&dev->xmit_lock);
+//	read_unlock_bh(&dev_mc_lock);
 
-        return;
+	return;
 }
 
+static struct tq_struct i2o_lan_set_mc_list_task = {
+		0, 0, (void (*)(void *))i2o_lan_set_mc_list, (void *) 0
+};
+
 /*
  * i2o_lan_set_multicast_list():
  *       Queue routine i2o_lan_set_mc_list() to be called later.
@@ -867,17 +1215,12 @@
 
 static void i2o_lan_set_multicast_list(struct net_device *dev)
 {
-        struct tq_struct *task;
-
-        task = (struct tq_struct *)kmalloc(sizeof(struct tq_struct), GFP_KERNEL);
-        if (task == NULL)
-                return;
-
-        task->next = NULL;
-        task->sync = 0;
-        task->routine = (void *)i2o_lan_set_mc_list;
-        task->data = (void *)dev;
-        queue_task(task, &tq_scheduler);
+	if (!in_interrupt()) {
+		i2o_lan_set_mc_list_task.data = (void *)dev;
+		queue_task(&i2o_lan_set_mc_list_task, &tq_scheduler);
+	} else {
+		i2o_lan_set_mc_list(dev);
+	}
 }
 
 /*
@@ -885,13 +1228,24 @@
  */
 static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu)
 {
-	if ((new_mtu < 68) || (new_mtu > 9000))
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
+	u32 max_pkt_size;
+
+	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
+		 	     0x0000, 6, &max_pkt_size, 4) < 0)
+		return -EFAULT;
+
+	if (new_mtu < 68 || max_pkt_size < new_mtu)
 		return -EINVAL;
-		
+
 	dev->mtu = new_mtu;
 	return 0;
 }
 
+/* Functions to initialize I2O LAN OSM:
+======================================*/
+
 /*
  * i2o_lan_register_device(): Register LAN class device to kernel.
  */
@@ -904,9 +1258,9 @@
 	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
 	void (*unregister_dev)(struct net_device *dev);
 
-	switch (i2o_dev->lct_data->sub_class) {
+	switch (i2o_dev->lct_data.sub_class) {
 	case I2O_LAN_ETHERNET:
-        	dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
+		dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
 		if (dev == NULL)
 			return NULL;
 		type_trans = eth_type_trans;
@@ -916,6 +1270,7 @@
 #ifdef CONFIG_ANYLAN
 	case I2O_LAN_100VG:
 		printk(KERN_ERR "i2o_lan: 100base VG not yet supported.\n");
+		return NULL;
 		break;
 #endif
 
@@ -925,7 +1280,7 @@
 		if (dev==NULL)
 			return NULL;
 		type_trans = tr_type_trans;
-		unregister_dev = unregister_trdev;		
+		unregister_dev = unregister_trdev;
 		break;
 #endif
 
@@ -933,92 +1288,122 @@
 	case I2O_LAN_FDDI:
 	{
 		int size = sizeof(struct net_device) + sizeof(struct i2o_lan_local)
-			   + sizeof("fddi%d ");
+			+ sizeof("fddi%d ");
 
-        	dev = (struct net_device *) kmalloc(size, GFP_KERNEL);
-        	memset((char *)dev, 0, size);
-            	dev->priv = (void *)(dev + 1);
-                dev->name = (char *)(dev + 1) + sizeof(struct i2o_lan_local);
+		dev = (struct net_device *) kmalloc(size, GFP_KERNEL);
+		if (dev == NULL)
+			return NULL;
+		memset((char *)dev, 0, size);
+	    	dev->priv = (void *)(dev + 1);
+		dev->name = (char *)(dev + 1) + sizeof(struct i2o_lan_local);
 
-		if (dev_alloc_name(dev,"fddi%d") < 0) {
+		if (dev_alloc_name(dev, "fddi%d") < 0) {
 			printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n");
 			kfree(dev);
 			return NULL;
 		}
 		type_trans = fddi_type_trans;
 		unregister_dev = (void *)unregister_netdevice;
-		
+
 		fddi_setup(dev);
 		register_netdev(dev);
-      	}
+	}
 	break;
 #endif
 
-#ifdef CONFIG_FIBRE_CHANNEL
+#ifdef CONFIG_NET_FC
 	case I2O_LAN_FIBRE_CHANNEL:
-		printk(KERN_INFO "i2o_lan: Fibre Channel not yet supported.\n");
-	break;
+		dev = init_fcdev(NULL, sizeof(struct i2o_lan_local));
+		if (dev == NULL)
+			return NULL;
+		type_trans = NULL;
+/* FIXME: Move fc_type_trans() from drivers/net/fc/iph5526.c to net/802/fc.c
+ * and export it in include/linux/fcdevice.h
+ *		type_trans = fc_type_trans;
+ */
+		unregister_dev = (void *)unregister_fcdev;
+		break;
 #endif
 
 	case I2O_LAN_UNKNOWN:
 	default:
-		printk(KERN_ERR "i2o_lan: LAN type 0x%08X not supported.\n",
-		       i2o_dev->lct_data->sub_class);
+		printk(KERN_ERR "i2o_lan: LAN type 0x%04x not supported.\n",
+		       i2o_dev->lct_data.sub_class);
 		return NULL;
 	}
 
 	priv = (struct i2o_lan_local *)dev->priv;
 	priv->i2o_dev = i2o_dev;
 	priv->type_trans = type_trans;
-	priv->bucket_count = 0;
 	priv->sgl_max = (i2o_dev->controller->inbound_size - 16) / 12;
+	atomic_set(&priv->buckets_out, 0);
+
+	/* Set default values for user configurable parameters */
+	/* Private values are changed via /proc file system */
+
+	priv->max_buckets_out = max_buckets_out;
+	priv->bucket_thresh   = bucket_thresh;
+	priv->rx_copybreak    = rx_copybreak;
+	priv->tx_batch_mode   = tx_batch_mode;
+	priv->i2o_event_mask  = i2o_event_mask;
+
+	priv->tx_lock	      = SPIN_LOCK_UNLOCKED;
+	priv->fbl_lock	      = SPIN_LOCK_UNLOCKED;
 
 	unit++;
 	i2o_landevs[unit] = dev;
 	priv->unit = unit;
 
-	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
+	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
 			     0x0001, 0, &hw_addr, sizeof(hw_addr)) < 0) {
-     		printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
+		printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
 		unit--;
 		unregister_dev(dev);
 		kfree(dev);
-      		return NULL;
+		return NULL;
 	}
 
-	dprintk("%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
-      		dev->name,hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3],
-      		hw_addr[4], hw_addr[5]);
+	dprintk(KERN_DEBUG "%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ 		dev->name, hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3],
+		hw_addr[4], hw_addr[5]);
 
 	dev->addr_len = 6;
 	memcpy(dev->dev_addr, hw_addr, 6);
 
-	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
-		0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0)
-	{
-      		printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
-      		unit--;
-      		unregister_dev(dev);
-      		kfree(dev);
-         	return NULL;
-	}
-   	dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out);
-   	priv->tx_max_out = tx_max_out;
-   	priv->tx_out	= 0;
-   	priv->tx_count	= 0;
-	priv->lock	= SPIN_LOCK_UNLOCKED;
+	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid,
+			     0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) {
+		printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
+		unit--;
+		unregister_dev(dev);
+		kfree(dev);
+		return NULL;
+	}
+	dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out);
+	priv->tx_max_out = tx_max_out;
+	atomic_set(&priv->tx_out, 0);
+	priv->tx_count = 0;
 
 	priv->i2o_batch_send_task.next    = NULL;
 	priv->i2o_batch_send_task.sync    = 0;
 	priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send;
 	priv->i2o_batch_send_task.data    = (void *)dev;
 
-	dev->open               = i2o_lan_open;
-	dev->stop               = i2o_lan_close;
-	dev->hard_start_xmit    = i2o_lan_packet_send;
-	dev->get_stats          = i2o_lan_get_stats;
+	dev->open		= i2o_lan_open;
+	dev->stop		= i2o_lan_close;
+	dev->get_stats		= i2o_lan_get_stats;
 	dev->set_multicast_list = i2o_lan_set_multicast_list;
-	dev->change_mtu		= i2o_lan_change_mtu;
+	dev->tx_timeout		= i2o_lan_tx_timeout;
+	dev->watchdog_timeo	= I2O_LAN_TX_TIMEOUT;
+
+#ifdef CONFIG_NET_FC
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_FIBRE_CHANNEL)
+		dev->hard_start_xmit = i2o_lan_sdu_send;
+	else
+#endif
+		dev->hard_start_xmit = i2o_lan_packet_send;
+
+	if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET)
+		dev->change_mtu	= i2o_lan_change_mtu;
 
 	return dev;
 }
@@ -1032,19 +1417,35 @@
 	struct net_device *dev;
 	int i;
 
-	printk(KERN_INFO "Linux I2O LAN OSM (c) 1999 University of Helsinki.\n");
+	printk(KERN_INFO "I2O LAN OSM (c) 1999 University of Helsinki.\n");
+
+	/* Module params used as global defaults for private values */
+
+	if (max_buckets_out > I2O_LAN_MAX_BUCKETS_OUT)
+		max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;
+	if (bucket_thresh > max_buckets_out)
+		bucket_thresh = max_buckets_out;
+
+	/* Install handlers for incoming replies */
+
+	if (i2o_install_handler(&i2o_lan_send_handler) < 0) {
+ 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
+		return -EINVAL;
+	}
+	lan_send_context = i2o_lan_send_handler.context;
 
-	if (bucketpost > I2O_BUCKET_COUNT)
-		bucketpost = I2O_BUCKET_COUNT;
-	if (bucketthresh > bucketpost)
-		bucketthresh = bucketpost;
+	if (i2o_install_handler(&i2o_lan_receive_handler) < 0) {
+ 		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
+		return -EINVAL;
+	}
+	lan_receive_context = i2o_lan_receive_handler.context;
 
 	if (i2o_install_handler(&i2o_lan_handler) < 0) {
  		printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
 		return -EINVAL;
 	}
 	lan_context = i2o_lan_handler.context;
-	
+
 	for(i=0; i <= MAX_LAN_CARDS; i++)
 		i2o_landevs[i] = NULL;
 
@@ -1052,15 +1453,16 @@
 		struct i2o_controller *iop = i2o_find_controller(i);
 		struct i2o_device *i2o_dev;
 
-		if (iop==NULL) continue;
+		if (iop==NULL)
+			continue;
 
 		for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) {
 
-			if (i2o_dev->lct_data->class_id != I2O_CLASS_LAN)
+			if (i2o_dev->lct_data.class_id != I2O_CLASS_LAN)
 				continue;
 
 			/* Make sure device not already claimed by an ISM */
-			if (i2o_dev->lct_data->user_tid != 0xFFF)
+			if (i2o_dev->lct_data.user_tid != 0xFFF)
 				continue;
 
 			if (unit == MAX_LAN_CARDS) {
@@ -1071,14 +1473,16 @@
 
 			dev = i2o_lan_register_device(i2o_dev);
  			if (dev == NULL) {
-				printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device.\n");
-				continue; // try next one
+				printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device 0x%04x.\n",
+				       i2o_dev->lct_data.sub_class);
+				continue;
 			}
 
-			printk(KERN_INFO "%s: I2O LAN device registered, tid = %d,"
-				" subclass = 0x%08X, unit = %d.\n",
-				dev->name, i2o_dev->lct_data->tid, i2o_dev->lct_data->sub_class,
-				((struct i2o_lan_local *)dev->priv)->unit);
+			printk(KERN_INFO "%s: I2O LAN device registered, "
+				"subclass = 0x%04x, unit = %d, tid = %d.\n",
+				dev->name, i2o_dev->lct_data.sub_class,
+				((struct i2o_lan_local *)dev->priv)->unit,
+				i2o_dev->lct_data.tid);
 		}
 
 		i2o_unlock_controller(iop);
@@ -1097,45 +1501,55 @@
 
 	for (i = 0; i <= unit; i++) {
 		struct net_device *dev = i2o_landevs[i];
-		struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
-		struct i2o_device *i2o_dev = priv->i2o_dev;	
+		struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+		struct i2o_device *i2o_dev = priv->i2o_dev;
 
-		switch (i2o_dev->lct_data->sub_class) {
+		switch (i2o_dev->lct_data.sub_class) {
 		case I2O_LAN_ETHERNET:
 			unregister_netdev(dev);
-			kfree(dev);
 			break;
 #ifdef CONFIG_FDDI
 		case I2O_LAN_FDDI:
 			unregister_netdevice(dev);
-			kfree(dev);
 			break;
 #endif
 #ifdef CONFIG_TR
 		case I2O_LAN_TR:
 			unregister_trdev(dev);
-			kfree(dev);
+			break;
+#endif
+#ifdef CONFIG_NET_FC
+		case I2O_LAN_FIBRE_CHANNEL:
+			unregister_fcdev(dev);
 			break;
 #endif
 		default:
-			printk(KERN_WARNING "i2o_lan: Spurious I2O LAN subclass 0x%08X.\n",
-			       i2o_dev->lct_data->sub_class);
+			printk(KERN_WARNING "%s: Spurious I2O LAN subclass 0x%08x.\n",
+			       dev->name, i2o_dev->lct_data.sub_class);
 		}
 
 		dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n",
 			dev->name);
+		kfree(dev);
 	}
 
 	i2o_remove_handler(&i2o_lan_handler);
+	i2o_remove_handler(&i2o_lan_send_handler);
+	i2o_remove_handler(&i2o_lan_receive_handler);
 }
 
 EXPORT_NO_SYMBOLS;
 
-MODULE_AUTHOR("Univ of Helsinki, CS Department");
+MODULE_AUTHOR("University of Helsinki, Department of Computer Science");
 MODULE_DESCRIPTION("I2O Lan OSM");
 
-MODULE_PARM(bucketpost, "i");   // Total number of buckets to post
-MODULE_PARM(bucketthresh, "i"); // Bucket post threshold
-MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
+MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)");
+MODULE_PARM(bucket_thresh, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
+MODULE_PARM_DESC(bucket_thresh, "Bucket post threshold (1-)");
+MODULE_PARM(rx_copybreak, "1-" "i");
+MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy only small frames (1-)");
+MODULE_PARM(tx_batch_mode, "0-1" "i");
+MODULE_PARM_DESC(tx_batch_mode, "0=Use immediate mode send, 1=Use batch mode send");
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h
--- v2.3.99-pre5/linux/drivers/i2o/i2o_lan.h	Tue Jan 11 22:31:40 2000
+++ linux/drivers/i2o/i2o_lan.h	Wed Apr 12 09:38:53 2000
@@ -1,24 +1,29 @@
 /*
- *   	i2o_lan.h		LAN Class specific definitions
+ *   	i2o_lan.h			I2O LAN Class definitions
  *
- *      I2O LAN CLASS OSM       Prototyping, May 17th 1999
+ *      I2O LAN CLASS OSM       	April 3rd 2000
  *
- *      (C) Copyright 1999      University of Helsinki,
- *                              Department of Computer Science
+ *      (C) Copyright 1999, 2000	University of Helsinki,
+ *					Department of Computer Science
  *
  *      This code is still under development / test.
  *
- *      Author:         Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>    
+ *	Author:		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *			Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
  */
 
 #ifndef _I2O_LAN_H
 #define _I2O_LAN_H
 
-/* Tunable parameters first */
+/* Default values for tunable parameters first */
 
-#define I2O_BUCKET_COUNT 	256
-#define I2O_BUCKET_THRESH	18 /* 9 buckets in one message */
+#define I2O_LAN_MAX_BUCKETS_OUT 256
+#define I2O_LAN_BUCKET_THRESH	18	/* 9 buckets in one message */
+#define I2O_LAN_RX_COPYBREAK	200
+#define I2O_LAN_TX_TIMEOUT 	(1*HZ)
+#define I2O_LAN_TX_BATCH_MODE	1	/* 1=on, 0=off */
+#define I2O_LAN_EVENT_MASK	0	/* 0=None, 0xFFC00002=All */
 
 /* LAN types */
 #define I2O_LAN_ETHERNET	0x0030
@@ -114,5 +119,38 @@
 #define I2O_LAN_EVT_LINK_DOWN		0x01
 #define I2O_LAN_EVT_LINK_UP		0x02
 #define I2O_LAN_EVT_MEDIA_CHANGE 	0x04
- 
+
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+
+struct i2o_lan_local {
+	u8 unit;
+	struct i2o_device *i2o_dev;
+	struct fddi_statistics stats;   /* see also struct net_device_stats */
+	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
+	atomic_t buckets_out;  		/* nbr of unused buckets on DDM */
+	atomic_t tx_out;		/* outstanding TXes */
+	u8 tx_count;  			/* packets in one TX message frame */
+	u16 tx_max_out;	   		/* DDM's Tx queue len */
+	u8 sgl_max;			/* max SGLs in one message frame */
+	u32 m;				/* IOP address of msg frame */
+
+	struct tq_struct i2o_batch_send_task;
+	int send_active;
+	struct sk_buff **i2o_fbl;	/* Free bucket list (to reuse skbs) */
+	int i2o_fbl_tail;
+	spinlock_t fbl_lock;
+
+	spinlock_t tx_lock;
+
+	/* LAN OSM configurable parameters are here: */
+
+	u16 max_buckets_out;		/* max nbr of buckets to send to DDM */
+	u16 bucket_thresh;		/* send more when this many used */
+	u16 rx_copybreak;
+
+	u8  tx_batch_mode;		/* Set when using batch mode sends */
+	u32 i2o_event_mask;		/* To turn on interesting event flags */
+};
+
 #endif /* _I2O_LAN_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.99-pre5/linux/drivers/i2o/i2o_pci.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/i2o/i2o_pci.c	Wed Apr 12 09:38:53 2000
@@ -53,8 +53,10 @@
 	iounmap(((u8 *)c->post_port)-0x40);
 
 #ifdef CONFIG_MTRR
-	if(c->bus.pci.mtrr_reg > 0)
-		mtrr_del(c->bus.pci.mtrr_reg, 0, 0);
+       if(c->bus.pci.mtrr_reg0 > 0)
+               mtrr_del(c->bus.pci.mtrr_reg0, 0, 0);
+       if(c->bus.pci.mtrr_reg1 > 0)
+               mtrr_del(c->bus.pci.mtrr_reg1, 0, 0);
 #endif
 }
 
@@ -176,8 +178,22 @@
 	 * Enable Write Combining MTRR for IOP's memory region
 	 */
 #ifdef CONFIG_MTRR
-	c->bus.pci.mtrr_reg = 
-		mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1);
+       c->bus.pci.mtrr_reg0 =
+                mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1);
+/*
+* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable
+* since the region contains the Messaging unit which shouldn't be cached.
+*/
+       c->bus.pci.mtrr_reg1 = -1;
+       if(dev->vendor == PCI_VENDOR_ID_INTEL)
+        {
+       printk(KERN_INFO "i2o_pci: MTRR workaround for Intel i960 processor\n"); 
+       c->bus.pci.mtrr_reg1 =
+                mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
+        if(c->bus.pci.mtrr_reg1< 0)
+                        printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
+       }
+
 #endif
 
 	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
@@ -230,7 +246,8 @@
 	
 	printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
 
-	pci_for_each_dev(dev) {
+	pci_for_each_dev(dev)	
+	{
 		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
 			continue;
 		if((dev->class&0xFF)>1)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.3.99-pre5/linux/drivers/i2o/i2o_proc.c	Tue Jan 11 22:31:40 2000
+++ linux/drivers/i2o/i2o_proc.c	Wed Apr 12 09:38:53 2000
@@ -29,7 +29,7 @@
 /*
  * TODO List
  *
- * - Add support for any version 2.0 spec changes once 2.0 IRTOS
+ * - Add support for any version 2.0 spec changes once 2.0 IRTOS is
  *   is available to test with
  * - Clean up code to use official structure definitions 
  */
@@ -64,6 +64,8 @@
 	write_proc_t *write_proc;	/* write func */
 } i2o_proc_entry;
 
+// #define DRIVERDEBUG
+
 static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *);
@@ -97,8 +99,12 @@
 				   struct proc_dir_entry * );
 static void i2o_proc_remove_controller(struct i2o_controller *, 
 				       struct proc_dir_entry * );
+static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *);
+static void i2o_proc_remove_device(struct i2o_device *);
 static int create_i2o_procfs(void);
 static int destroy_i2o_procfs(void);
+static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *);
+static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *);
 
 static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *,
 				      void *);
@@ -130,6 +136,20 @@
 static struct proc_dir_entry *i2o_proc_dir_root;
 
 /*
+ * I2O OSM descriptor
+ */
+static struct i2o_handler i2o_proc_handler =
+{
+	NULL,
+	i2o_proc_new_dev,
+	i2o_proc_dev_del,
+	NULL,
+	"I2O procfs Layer",
+	0,
+	0xffffffff	// All classes
+};
+
+/*
  * IOP specific entries...write field just in case someone 
  * ever wants one.
  */
@@ -240,6 +260,7 @@
 	{NULL, 0, NULL, NULL}
 };
 
+
 static char *chtostr(u8 *chars, int n)
 {
 	char tmp[256];
@@ -412,6 +433,9 @@
 	if(lct->boot_tid)	
 		len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid);
 
+	len += 
+		sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind);
+
 	for(i = 0; i < entries; i++)
 	{
 		len += sprintf(buf+len, "Entry %d\n", i);
@@ -1024,7 +1048,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid, 0xF000, -1, NULL, 0,
+				d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0,
 				&result, sizeof(result));
 
 	if (token < 0) {
@@ -1088,7 +1112,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid,
+				d->controller, d->lct_data.tid,
 				0xF001, -1, NULL, 0,
 				&result, sizeof(result));
 
@@ -1137,7 +1161,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid,
+				d->controller, d->lct_data.tid,
 				0xF002, -1, NULL, 0,
 				&result, sizeof(result));
 
@@ -1196,7 +1220,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid,
+				d->controller, d->lct_data.tid,
 				0xF003, -1, NULL, 0,
 				&result, sizeof(result));
 
@@ -1255,7 +1279,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid,
+				d->controller, d->lct_data.tid,
 				0xF000, -1,
 				NULL, 0,
 				&result, sizeof(result));
@@ -1310,7 +1334,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid,
+				d->controller, d->lct_data.tid,
 				0xF006, -1,
 				NULL, 0,
 				&result, sizeof(result));
@@ -1352,7 +1376,7 @@
 	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				0xF100,	-1,
 				&work32, sizeof(work32));
 
@@ -1421,7 +1445,7 @@
 	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid, 
+	token = i2o_query_scalar(d->controller, d->lct_data.tid, 
 				0xF101,	-1,
 				&result, sizeof(result));
 
@@ -1464,7 +1488,7 @@
 	spin_lock(&i2o_proc_lock);
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				0xF102,	-1,
 				&result, sizeof(result));
 
@@ -1497,7 +1521,7 @@
 	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid, 
+	token = i2o_query_scalar(d->controller, d->lct_data.tid, 
 				 0xF103, -1,
 				 &work32, sizeof(work32));
 
@@ -1573,7 +1597,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0xF200, -1,
 				 &result, sizeof(result));
 
@@ -2020,7 +2044,7 @@
 	spin_lock(&i2o_proc_lock);
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0000, -1, &work32, 56*4);
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info");
@@ -2142,7 +2166,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0001, -1, &work32, 48*4);
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address");
@@ -2240,7 +2264,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid, 0x0002, -1, 
+				d->controller, d->lct_data.tid, 0x0002, -1, 
 				NULL, 0, &result, sizeof(result));
 
 	if (token < 0) {
@@ -2275,7 +2299,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0003, -1, &work32, 9*4);
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control");
@@ -2316,7 +2340,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0004, -1, &work32, 20);
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation");
@@ -2389,7 +2413,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0005, -1, &result, sizeof(result));
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation");
@@ -2471,7 +2495,7 @@
 	len = 0;
 
 	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-				d->controller, d->lct_data->tid,
+				d->controller, d->lct_data.tid,
 				0x0006, -1, NULL, 0, &result, sizeof(result));
 
 	if (token < 0) {
@@ -2506,7 +2530,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0007, -1, &work32, 8*4);
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info");
@@ -2558,7 +2582,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0008, -1, &work32, 8*4);
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info");
@@ -2675,7 +2699,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0100, -1, &stats, sizeof(stats));
 	if (token < 0) {
 		len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics");
@@ -2705,7 +2729,7 @@
 	/* Optional statistics follows */
 	/* Get 0x0180 to see which optional groups/fields are supported */
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0180, -1, &supp_groups, sizeof(supp_groups));
 	
 	if (token < 0) {
@@ -2716,7 +2740,7 @@
 
 	if (supp_groups[1]) /* 0x0182 */
 	{
-		token = i2o_query_scalar(d->controller, d->lct_data->tid,
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 	0x0182, -1, &tx_stats, sizeof(tx_stats));
 
 		if (token < 0) {
@@ -2749,7 +2773,7 @@
 
 	if (supp_groups[2]) /* 0x0183 */
 	{
-		token = i2o_query_scalar(d->controller, d->lct_data->tid,
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
 					 0x0183, -1, &rx_stats, sizeof(rx_stats));
 		if (token < 0) {
 			len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats");
@@ -2785,7 +2809,7 @@
 	
 	if (supp_groups[3]) /* 0x0184 */
 	{
-		token = i2o_query_scalar(d->controller, d->lct_data->tid,
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 	0x0184, -1, &chksum_stats, sizeof(chksum_stats));
 
 		if (token < 0) {
@@ -2864,7 +2888,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0200, -1, &stats, sizeof(stats));
 
 	if (token < 0) {
@@ -2893,7 +2917,7 @@
 	/* Optional Ethernet statistics follows  */
 	/* Get 0x0280 to see which optional fields are supported */
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0280, -1, &supp_fields, sizeof(supp_fields));
 
 	if (token < 0) {
@@ -2904,7 +2928,7 @@
 
 	if (supp_fields) /* 0x0281 */
 	{
-		token = i2o_query_scalar(d->controller, d->lct_data->tid,
+		token = i2o_query_scalar(d->controller, d->lct_data.tid,
 					 0x0281, -1, &stats, sizeof(stats));
 
 		if (token < 0) {
@@ -2959,7 +2983,7 @@
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0300, -1, &work64, sizeof(work64));
 
 	if (token < 0) {
@@ -3053,7 +3077,7 @@
 	spin_lock(&i2o_proc_lock);
 	len = 0;
 
-	token = i2o_query_scalar(d->controller, d->lct_data->tid,
+	token = i2o_query_scalar(d->controller, d->lct_data.tid,
 				 0x0400, -1, &work64, sizeof(work64));
 
 	if (token < 0) {
@@ -3135,78 +3159,117 @@
 	
 	for(dev = pctrl->devices; dev; dev = dev->next)
 	{
-		sprintf(buff, "%0#5x", dev->lct_data->tid);
+		sprintf(buff, "%0#5x", dev->lct_data.tid);
 
 		dir1 = proc_mkdir(buff, dir);
 		dev->proc_entry = dir1;
 
 		if(!dir1)
 			printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n");
-		
-		i2o_proc_create_entries(dev, generic_dev_entries, dir1);
 
-		switch(dev->lct_data->class_id)
-		{
+		i2o_proc_add_device(dev, dir1);
+	}
+
+	return 0;
+}
+
+void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d)
+{
+	char buff[10];
+
+#ifdef DRIVERDEBUG
+	printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit);
+#endif
+	sprintf(buff, "%0#5x", d->lct_data.tid);
+
+	d->proc_entry = proc_mkdir(buff, c->proc_entry);
+
+	if(!d->proc_entry)
+	{
+		printk(KERN_WARNING "i2o: Could not allocate procdir!\n");
+		return;
+	}
+
+	i2o_proc_add_device(d, d->proc_entry);
+}
+
+void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir)
+{	
+	i2o_proc_create_entries(dev, generic_dev_entries, dir);
+
+	/* Inform core that we want updates about this device's status */
+	i2o_device_notify_on(dev, &i2o_proc_handler);
+	switch(dev->lct_data.class_id)
+	{
 		case I2O_CLASS_SCSI_PERIPHERAL:
 		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-			i2o_proc_create_entries(dev, rbs_dev_entries, dir1);
+			i2o_proc_create_entries(dev, rbs_dev_entries, dir);
 			break;
 		case I2O_CLASS_LAN:
-			i2o_proc_create_entries(dev, lan_entries, dir1);
-			switch(dev->lct_data->sub_class)
+			i2o_proc_create_entries(dev, lan_entries, dir);
+			switch(dev->lct_data.sub_class)
 			{
-			case I2O_LAN_ETHERNET:
-				i2o_proc_create_entries(dev, lan_eth_entries,
-							dir1);
-				break;
-			case I2O_LAN_FDDI:
-				i2o_proc_create_entries(dev, lan_fddi_entries,
-							dir1);
-				break;
-			case I2O_LAN_TR:
-				i2o_proc_create_entries(dev, lan_tr_entries,
-							dir1);
-				break;
-			default:
-				break;
+				case I2O_LAN_ETHERNET:
+					i2o_proc_create_entries(dev, lan_eth_entries, dir);
+					break;
+				case I2O_LAN_FDDI:
+					i2o_proc_create_entries(dev, lan_fddi_entries, dir);
+					break;
+				case I2O_LAN_TR:
+					i2o_proc_create_entries(dev, lan_tr_entries, dir);
+					break;
+				default:
+					break;
 			}
 			break;
 		default:
 			break;
-		}
 	}
-
-	return 0;
 }
 
 static void i2o_proc_remove_controller(struct i2o_controller *pctrl, 
 				       struct proc_dir_entry *parent)
 {
 	char buff[10];
-	char dev_id[10];
-	struct proc_dir_entry *de;
 	struct i2o_device *dev;
 
 	/* Remove unused device entries */
 	for(dev=pctrl->devices; dev; dev=dev->next)
+		i2o_proc_remove_device(dev);
+
+	if(!pctrl->proc_entry->count)
 	{
-		de=dev->proc_entry;
-		sprintf(dev_id, "%0#5x", dev->lct_data->tid);
+		sprintf(buff, "iop%d", pctrl->unit);
 
-		/* Would it be safe to remove _files_ even if they are in use? */
-		if((de) && (!de->count))
-		{
-			i2o_proc_remove_entries(generic_dev_entries, de);
+		i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
 
-			switch(dev->lct_data->class_id)
-			{
+		remove_proc_entry(buff, parent);
+		pctrl->proc_entry = NULL;
+	}
+}
+
+void i2o_proc_remove_device(struct i2o_device *dev)
+{
+	struct proc_dir_entry *de=dev->proc_entry;
+	char dev_id[10];
+
+	sprintf(dev_id, "%0#5x", dev->lct_data.tid);
+
+	i2o_device_notify_off(dev, &i2o_proc_handler);
+	/* Would it be safe to remove _files_ even if they are in use? */
+	if((de) && (!de->count))
+	{
+		i2o_proc_remove_entries(generic_dev_entries, de);
+		switch(dev->lct_data.class_id)
+		{
 			case I2O_CLASS_SCSI_PERIPHERAL:
 			case I2O_CLASS_RANDOM_BLOCK_STORAGE:
 				i2o_proc_remove_entries(rbs_dev_entries, de);
 				break;
 			case I2O_CLASS_LAN:
+			{
 				i2o_proc_remove_entries(lan_entries, de);
-				switch(dev->lct_data->sub_class)
+				switch(dev->lct_data.sub_class)
 				{
 				case I2O_LAN_ETHERNET:
 					i2o_proc_remove_entries(lan_eth_entries, de);
@@ -3219,19 +3282,19 @@
 					break;
 				}
 			}
-			remove_proc_entry(dev_id, parent);
+			remove_proc_entry(dev_id, dev->controller->proc_entry);
 		}
 	}
+}
+	
+void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d)
+{
+#ifdef DRIVERDEBUG
+	printk(KERN_INFO, "Deleting device %d from iop%d\n", 
+		d->lct_data.tid, c->unit);
+#endif
 
-	if(!pctrl->proc_entry->count)
-	{
-		sprintf(buff, "iop%d", pctrl->unit);
-
-		i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
-
-		remove_proc_entry(buff, parent);
-		pctrl->proc_entry = NULL;
-	}
+	i2o_proc_remove_device(d);
 }
 
 static int create_i2o_procfs(void)
@@ -3278,13 +3341,19 @@
 
 	return 0;
 }
-		
+
 #ifdef MODULE
 #define i2o_proc_init init_module
 #endif
 
 int __init i2o_proc_init(void)
 {
+	if (i2o_install_handler(&i2o_proc_handler) < 0)
+	{
+		printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n");
+		return 0;
+	}
+
 	if(create_i2o_procfs())
 		return -EBUSY;
 
@@ -3293,12 +3362,12 @@
 
 #ifdef MODULE
 
-
 MODULE_AUTHOR("Deepak Saxena");
 MODULE_DESCRIPTION("I2O procfs Handler");
 
 void cleanup_module(void)
 {
 	destroy_i2o_procfs();
+	i2o_remove_handler(&i2o_proc_handler);
 }
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c
--- v2.3.99-pre5/linux/drivers/i2o/i2o_scsi.c	Tue Nov 23 22:42:20 1999
+++ linux/drivers/i2o/i2o_scsi.c	Wed Apr 12 09:38:53 2000
@@ -288,6 +288,9 @@
 struct i2o_handler i2o_scsi_handler=
 {
 	i2o_scsi_reply,
+	NULL,
+	NULL,
+	NULL,
 	"I2O SCSI OSM",
 	0,
 	I2O_CLASS_SCSI_PERIPHERAL
@@ -297,12 +300,12 @@
 {
 	u8 reply[8];
 	
-	if(i2o_query_scalar(c, d->lct_data->tid, 0, 3, reply, 4)<0)
+	if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0)
 		return -1;
 		
 	*target=reply[0];
 	
-	if(i2o_query_scalar(c, d->lct_data->tid, 0, 4, reply, 8)<0)
+	if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0)
 		return -1;
 
 	*lun=reply[1];
@@ -319,7 +322,7 @@
 	int target;
 	
 	h->controller=c;
-	h->bus_task=d->lct_data->tid;
+	h->bus_task=d->lct_data.tid;
 	
 	for(target=0;target<16;target++)
 		for(lun=0;lun<8;lun++)
@@ -328,33 +331,33 @@
 	for(unit=c->devices;unit!=NULL;unit=unit->next)
 	{
 		dprintk(("Class %03X, parent %d, want %d.\n",
-			unit->lct_data->class_id, unit->lct_data->parent_tid, d->lct_data->tid));
+			unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid));
 			
 		/* Only look at scsi and fc devices */
-		if (    (unit->lct_data->class_id != I2O_CLASS_SCSI_PERIPHERAL)
-		     && (unit->lct_data->class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL)
+		if (    (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL)
+		     && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL)
 		   )
 			continue;
 
 		/* On our bus ? */
-		dprintk(("Found a disk (%d).\n", unit->lct_data->tid));
-		if ((unit->lct_data->parent_tid == d->lct_data->tid)
-		     || (unit->lct_data->parent_tid == d->lct_data->parent_tid)
+		dprintk(("Found a disk (%d).\n", unit->lct_data.tid));
+		if ((unit->lct_data.parent_tid == d->lct_data.tid)
+		     || (unit->lct_data.parent_tid == d->lct_data.parent_tid)
 		   )
 		{
 			u16 limit;
 			dprintk(("Its ours.\n"));
 			if(i2o_find_lun(c, unit, &target, &lun)==-1)
 			{
-				printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data->tid);
+				printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid);
 				continue;
 			}
 			dprintk(("Found disk %d %d.\n", target, lun));
-			h->task[target][lun]=unit->lct_data->tid;
+			h->task[target][lun]=unit->lct_data.tid;
 			h->tagclock[target][lun]=jiffies;
 
 			/* Get the max fragments/request */
-			i2o_query_scalar(c, d->lct_data->tid, 0xF103, 3, &limit, 2);
+			i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2);
 			
 			/* sanity */
 			if ( limit == 0 )
@@ -428,8 +431,8 @@
 			/*
 			 *	bus_adapter, SCSI (obsolete), or FibreChannel busses only
 			 */
-			if(    (d->lct_data->class_id!=I2O_CLASS_BUS_ADAPTER_PORT)	// bus_adapter
-//			    && (d->lct_data->class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT)	// FC_PORT
+			if(    (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT)	// bus_adapter
+//			    && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT)	// FC_PORT
 			  )
 				continue;
 		
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/Config.in linux/drivers/ide/Config.in
--- v2.3.99-pre5/linux/drivers/ide/Config.in	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/Config.in	Mon Apr 24 18:59:07 2000
@@ -16,7 +16,7 @@
    dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
-   dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+   dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
    comment 'IDE chipset support/bugfixes'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
@@ -35,8 +35,8 @@
 	    define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL $CONFIG_EXPERIMENTAL
 	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
 	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING $CONFIG_BLK_DEV_AEC6210 $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '      AEC62XX Tuning support (WIP)' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX $CONFIG_IDEDMA_PCI_WIP
 	    dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
 	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD7409 $CONFIG_BLK_DEV_IDEDMA_PCI
@@ -62,6 +62,7 @@
 	    dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
 	    dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '      VIA82CXXX Tuning support (WIP)' CONFIG_VIA82CXXX_TUNING $CONFIG_BLK_DEV_VIA82CXXX $CONFIG_IDEDMA_PCI_WIP
          fi
 	 if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
 	    bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
@@ -122,7 +123,7 @@
 fi
 
 if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
-     "$CONFIG_BLK_DEV_AEC6210" = "y" -o \
+     "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
      "$CONFIG_BLK_DEV_AMD7409" = "y" -o \
      "$CONFIG_BLK_DEV_CMD640" = "y" -o \
@@ -136,7 +137,8 @@
      "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
      "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
-     "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
+     "$CONFIG_BLK_DEV_SL82C105" = "y" -o \
+     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" ]; then
    define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
    define_bool CONFIG_BLK_DEV_IDE_MODES n
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/Makefile linux/drivers/ide/Makefile
--- v2.3.99-pre5/linux/drivers/ide/Makefile	Tue Mar 14 19:10:39 2000
+++ linux/drivers/ide/Makefile	Thu Apr 13 22:54:26 2000
@@ -25,8 +25,8 @@
 LX_OBJS :=
 MX_OBJS :=
 
-ifeq ($(CONFIG_BLK_DEV_AEC6210),y)
-IDE_OBJS += aec6210.o
+ifeq ($(CONFIG_BLK_DEV_AEC62XX),y)
+IDE_OBJS += aec62xx.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_ALI14XX),y)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/aec6210.c linux/drivers/ide/aec6210.c
--- v2.3.99-pre5/linux/drivers/ide/aec6210.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/aec6210.c	Wed Dec 31 16:00:00 1969
@@ -1,376 +0,0 @@
-/*
- * linux/drivers/ide/aec6210.c		Version 0.06	Mar. 18, 2000
- *
- * Copyright (C) 1998-2000	Andre Hedrick (andre@suse.com)
- * May be copied or modified under the terms of the GNU General Public License
- *
- *  pio 0 ::       40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02
- *  pio 1 ::       40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02
- *  pio 2 ::       40: 08 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02
- *  pio 3 ::       40: 03 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *  pio 4 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *  dma 0 ::       40: 0a 07 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *  dma 1 ::       40: 02 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *  dma 2 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *                 50: ff ff ff ff 00 06 04 00 00 00 00 00 00 00 00 00
- *
- * udma 0 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *                 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00
- *
- * udma 1 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *                 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00
- *
- * udma 2 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *                 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00
- *
- * auto   ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
- *                 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00
- *
- * auto   ::       40: 01 04 01 04 01 04 01 04 02 05 a6 cf 00 02 00 02
- *                 50: ff ff ff ff aa 06 04 00 00 00 00 00 00 00 00 00
- *
- *                 NO-Devices
- *                 40: 00 00 00 00 00 00 00 00 02 05 a6 00 00 02 00 02
- *                 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define ACARD_DEBUG_DRIVE_INFO		0
-
-#undef DISPLAY_AEC6210_TIMINGS
-
-#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int aec6210_get_info(char *, char **, off_t, int);
-extern int (*aec6210_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int aec6210_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-
-	u32 bibma = bmide_dev->resource[4].start;
-	u8 c0 = 0, c1 = 0;
-	
-	p += sprintf(p, "\n                                AEC6210 Chipset.\n");
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif	/* defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte aec6210_proc = 0;
-
-#ifdef CONFIG_AEC6210_TUNING
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-	unsigned short	chipset_settings;
-	byte		ultra_settings;
-};
-
-struct chipset_bus_clock_list_entry aec6210_base [] = {
-	{	XFER_UDMA_2,	0x0401,	0x02	},
-	{	XFER_UDMA_1,	0x0401,	0x01	},
-	{	XFER_UDMA_0,	0x0401,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x0401,	0x00	},
-	{	XFER_MW_DMA_1,	0x0402,	0x00	},
-	{	XFER_MW_DMA_0,	0x070a,	0x00	},
-
-	{	XFER_PIO_4,	0x0401,	0x00	},
-	{	XFER_PIO_3,	0x0403,	0x00	},
-	{	XFER_PIO_2,	0x0708,	0x00	},
-	{	XFER_PIO_1,	0x070a,	0x00	},
-	{	XFER_PIO_0,	0x0700,	0x00	},
-	{	0,		0x0000,	0x00	}
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * TO DO: active tuning and correction of cards without a bios.
- */
-
-static unsigned short pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->chipset_settings;
-		}
-	return 0x0000;
-}
-
-static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->ultra_settings;
-		}
-	return 0x00;
-}
-
-static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-
-	int			err;
-	byte			drive_pci;
-	unsigned short		drive_conf = 0x0000;
-	byte			ultra = 0x00, ultra_conf = 0x00;
-	byte			tmp1 = 0x00, tmp2 = 0x00;
-
-	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-
-	switch(drive_number) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return -1;
-	}
-
-	pci_read_config_word(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
-	drive_conf = pci_bus_clock_list(speed, aec6210_base);
-	pci_write_config_word(HWIF(drive)->pci_dev, drive_pci, drive_conf);
-
-	pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &ultra);
-	tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec6210_base);
-	tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number))));
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x54, tmp2);
-
-	err = ide_config_drive_speed(drive, speed);
-
-#if ACARD_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d 0x04%x 0x02%x 0x02%x 0x02%x 0x02%x\n",
-		drive->name, ide_xfer_verbose(speed), drive_number,
-		drive_conf, ultra, tmp1, ultra_conf, tmp2);
-#endif /* ACARD_DEBUG_DRIVE_INFO */
-
-	return(err);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id = drive->id;
-	byte speed = -1;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if (((id->dma_ultra & 0x0010) ||
-	     (id->dma_ultra & 0x0008) ||
-	     (id->dma_ultra & 0x0004)) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-	(void) aec6210_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static void aec6210_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 5:
-			speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-		case 4:
-			speed = XFER_PIO_4; break;
-		case 3:
-			speed = XFER_PIO_3; break;
-		case 2:
-			speed = XFER_PIO_2; break;
-		case 1:
-			speed = XFER_PIO_1; break;
-		default:
-			speed = XFER_PIO_0; break;
-	}
-	(void) aec6210_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x001F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		aec6210_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * aec6210_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC6210_TUNING */
-
-unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
-{
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-
-#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS)
-	aec6210_proc = 1;
-	bmide_dev = dev;
-	aec6210_display_info = &aec6210_get_info;
-#endif /* DISPLAY_AEC6210_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-void __init ide_init_aec6210 (ide_hwif_t *hwif)
-{
-#ifdef CONFIG_AEC6210_TUNING
-	hwif->tuneproc = &aec6210_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &aec6210_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC6210_TUNING */
-}
-
-void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	byte dma_new	= 0;
-	byte dma_old	= inb(dmabase+2);
-	byte reg54h	= 0;
-	byte masterdma	= hwif->channel ? 0x30 : 0x03;
-	byte slavedma	= hwif->channel ? 0xc0 : 0x0c;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	dma_new = dma_old;
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-
-	if (reg54h & masterdma)	dma_new |= 0x20;
-	if (reg54h & slavedma)	dma_new |= 0x40;
-	if (dma_new != dma_old)	outb(dma_new, dmabase+2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/aec62xx.c linux/drivers/ide/aec62xx.c
--- v2.3.99-pre5/linux/drivers/ide/aec62xx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ide/aec62xx.c	Thu Apr 13 22:54:26 2000
@@ -0,0 +1,553 @@
+/*
+ * linux/drivers/ide/aec62xx.c		Version 0.08	Mar. 28, 2000
+ *
+ * Copyright (C) 2000	Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+#define DISPLAY_AEC62XX_TIMINGS
+
+#ifndef HIGH_4
+#define HIGH_4(H)		((H)=(H>>4))
+#endif
+#ifndef LOW_4
+#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
+#endif
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+#ifndef MAKE_WORD
+#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
+#endif
+
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int aec62xx_get_info(char *, char **, off_t, int);
+extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+
+	u32 bibma = bmide_dev->resource[4].start;
+	u8 c0 = 0, c1 = 0;
+	u8 art = 0, uart = 0;
+
+	switch(bmide_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			p += sprintf(p, "\n                                AEC6210 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+			p += sprintf(p, "\n                                AEC6260 No Bios Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			p += sprintf(p, "\n                                AEC6260 Chipset.\n");
+			break;
+		default:
+			p += sprintf(p, "\n                                AEC62?? Chipset.\n");
+			break;
+	}
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	c0 = inb_p((unsigned short)bibma + 0x02);
+	c1 = inb_p((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+	(void) pci_read_config_byte(bmide_dev, 0x4a, &art);
+	p += sprintf(p, "                %sabled                         %sabled\n",
+		(art&0x02)?" en":"dis",(art&0x04)?" en":"dis");
+	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
+		(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+
+	switch(bmide_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			(void) pci_read_config_byte(bmide_dev, 0x54, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
+				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+				(art&0x02)?"2":(art&0x01)?"1":"0",
+				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+				(art&0x08)?"2":(art&0x04)?"1":"0",
+				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+				(art&0x20)?"2":(art&0x10)?"1":"0",
+				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+				(art&0x80)?"2":(art&0x40)?"1":"0");
+			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", art);
+			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(bmide_dev, 0x46, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
+			p += sprintf(p, "Recovery:       0x%02x", art);
+			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(bmide_dev, 0x47, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
+				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
+				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
+			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
+			p += sprintf(p, "         %s(%s)           %s(%s)\n",
+				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
+				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
+			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
+			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", LOW_4(art));
+			(void) pci_read_config_byte(bmide_dev, 0x49, &uart);
+			p += sprintf(p, "reg49h = 0x%02x ", uart);
+			(void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
+			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
+			break;
+		default:
+			break;
+	}
+
+	return p-buffer;/* => must be less than 4k! */
+}
+#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte aec62xx_proc = 0;
+
+#ifdef CONFIG_AEC62XX_TUNING
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+
+	byte		chipset_settings_34;
+	byte		ultra_settings_34;
+
+	byte		chipset_settings_33;
+	byte		ultra_settings_33;
+};
+
+struct chipset_bus_clock_list_entry aec62xx_base [] = {
+	{	XFER_UDMA_4,	0x41,	0x04,	0x31,	0x05	},
+	{	XFER_UDMA_3,	0x41,	0x03,	0x31,	0x04	},
+	{	XFER_UDMA_2,	0x41,	0x02,	0x31,	0x03	},
+	{	XFER_UDMA_1,	0x41,	0x01,	0x31,	0x02	},
+	{	XFER_UDMA_0,	0x41,	0x01,	0x31,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x41,	0x00,	0x31,	0x00	},
+	{	XFER_MW_DMA_1,	0x42,	0x00,	0x31,	0x00	},
+	{	XFER_MW_DMA_0,	0x7a,	0x00,	0x0a,	0x00	},
+
+	{	XFER_PIO_4,	0x41,	0x00,	0x31,	0x00	},
+	{	XFER_PIO_3,	0x43,	0x00,	0x33,	0x00	},
+	{	XFER_PIO_2,	0x78,	0x00,	0x08,	0x00	},
+	{	XFER_PIO_1,	0x7a,	0x00,	0x0a,	0x00	},
+	{	XFER_PIO_0,	0x70,	0x00,	0x00,	0x00	},
+	{	0,		0x00,	0x00,	0x00,	0x00	}
+};
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
+
+static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return ((byte) ((1) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
+		}
+	return 0x00;
+}
+
+static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return ((byte) ((1) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
+		}
+	return 0x00;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte unit		= (drive->select.b.unit & 0x01);
+	int drive_number	= ((hwif->channel ? 2 : 0) + unit);
+	int err			= 0;
+	unsigned short d_conf	= 0x0000;
+	byte ultra		= 0x00;
+	byte ultra_conf		= 0x00;
+	byte tmp0		= 0x00;
+	byte tmp1		= 0x00;
+	byte tmp2		= 0x00;
+	unsigned long flags;
+
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
+
+	pci_read_config_word(dev, 0x40|(2*drive_number), &d_conf);
+	tmp0 = pci_bus_clock_list(speed, aec62xx_base);
+	SPLIT_BYTE(tmp0,tmp1,tmp2);
+	MAKE_WORD(d_conf,tmp1,tmp2);
+	pci_write_config_word(dev, 0x40|(2*drive_number), d_conf);
+
+	tmp1 = 0x00;
+	tmp2 = 0x00;
+	pci_read_config_byte(dev, 0x54, &ultra);
+	tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
+	tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number))));
+	pci_write_config_byte(dev, 0x54, tmp2);
+
+	__restore_flags(flags);	/* local CPU only */
+
+	err = ide_config_drive_speed(drive, speed);
+	return(err);
+}
+
+static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte unit		= (drive->select.b.unit & 0x01);
+	int drive_number	= ((hwif->channel ? 2 : 0) + unit);
+	byte ultra_pci		= hwif->channel ? 0x45 : 0x44;
+	int err			= 0;
+	byte drive_conf		= 0x00;
+	byte ultra_conf		= 0x00;
+	byte ultra		= 0x00;
+	byte tmp1		= 0x00;
+	byte tmp2		= 0x00;
+
+	unsigned long flags;
+
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
+
+	pci_read_config_byte(dev, 0x40|drive_number, &drive_conf);
+	drive_conf = pci_bus_clock_list(speed, aec62xx_base);
+	pci_write_config_byte(dev, 0x40|drive_number, drive_conf);
+
+	pci_read_config_byte(dev, ultra_pci, &ultra);
+	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
+	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+	pci_write_config_byte(dev, ultra_pci, tmp2);
+	__restore_flags(flags);	/* local CPU only */
+
+	err = ide_config_drive_speed(drive, speed);
+	return(err);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	byte unit		= (drive->select.b.unit & 0x01);
+	unsigned long dma_base	= hwif->dma_base;
+	byte speed		= -1;
+
+	if (drive->media != ide_disk)
+		return ((int) ide_dma_off_quietly);
+
+	if (((id->dma_ultra & 0x0010) ||
+	     (id->dma_ultra & 0x0008) ||
+	     (id->dma_ultra & 0x0004)) && (ultra)) {
+		speed = XFER_UDMA_2;
+	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
+		speed = XFER_UDMA_1;
+	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
+		speed = XFER_UDMA_0;
+	} else if (id->dma_mword & 0x0004) {
+		speed = XFER_MW_DMA_2;
+	} else if (id->dma_mword & 0x0002) {
+		speed = XFER_MW_DMA_1;
+	} else if (id->dma_mword & 0x0001) {
+		speed = XFER_MW_DMA_0;
+	} else if (id->dma_1word & 0x0004) {
+		speed = XFER_SW_DMA_2;
+	} else if (id->dma_1word & 0x0002) {
+		speed = XFER_SW_DMA_1;
+	} else if (id->dma_1word & 0x0001) {
+		speed = XFER_SW_DMA_0;
+	} else {
+ 		return ((int) ide_dma_off_quietly);
+ 	}
+
+	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+	(void) aec6210_tune_chipset(drive, speed);
+
+	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+}
+
+static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	byte unit		= (drive->select.b.unit & 0x01);
+	unsigned long dma_base	= hwif->dma_base;
+	byte speed		= -1;
+	byte ultra66		= ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
+
+	if (drive->media != ide_disk)
+		return ((int) ide_dma_off_quietly);
+
+	if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) {
+		speed = XFER_UDMA_4;
+	} else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) {
+		speed = XFER_UDMA_3;
+	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
+		speed = XFER_UDMA_2;
+	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
+		speed = XFER_UDMA_1;
+	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
+		speed = XFER_UDMA_0;
+	} else if (id->dma_mword & 0x0004) {
+		speed = XFER_MW_DMA_2;
+	} else if (id->dma_mword & 0x0002) {
+		speed = XFER_MW_DMA_1;
+	} else if (id->dma_mword & 0x0001) {
+		speed = XFER_MW_DMA_0;
+	} else if (id->dma_1word & 0x0004) {
+		speed = XFER_SW_DMA_2;
+	} else if (id->dma_1word & 0x0002) {
+		speed = XFER_SW_DMA_1;
+	} else if (id->dma_1word & 0x0001) {
+		speed = XFER_SW_DMA_0;
+	} else {
+		return ((int) ide_dma_off_quietly);
+	}
+
+	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+	(void) aec6260_tune_chipset(drive, speed);
+
+	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
+{
+	switch(HWIF(drive)->pci_dev->device) {	
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			return config_aec6210_chipset_for_dma(drive, ultra);
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			return config_aec6260_chipset_for_dma(drive, ultra);
+		default:
+			return ((int) ide_dma_off_quietly);
+	}
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
+{
+	byte speed;
+	byte new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	switch(pio) {
+		case 5:		speed = new_pio; break;
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			(void) aec6210_tune_chipset(drive, speed);
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			(void) aec6260_tune_chipset(drive, speed);
+		default:
+			break;
+        }
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x001F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive, 1);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive, 0);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive, 0);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		aec62xx_tune_drive(drive, 5);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif /* CONFIG_AEC62XX_TUNING */
+
+unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!aec62xx_proc) {
+		aec62xx_proc = 1;
+		bmide_dev = dev;
+		aec62xx_display_info = &aec62xx_get_info;
+	}
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
+{
+	byte mask	= hwif->channel ? 0x02 : 0x01;
+	byte ata66	= 0;
+
+	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
+#if 1
+	printk("AEC6260: reg49h=0x%02x ATA-%s Cable Port%d\n", ata66, (ata66 & mask) ? "33" : "66", hwif->channel);
+#endif
+	return ((ata66 & mask) ? 0 : 1);
+}
+
+void __init ide_init_aec62xx (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_AEC62XX_TUNING
+	hwif->tuneproc = &aec62xx_tune_drive;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (hwif->dma_base)
+		hwif->dmaproc = &aec62xx_dmaproc;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif /* CONFIG_AEC62XX_TUNING */
+}
+
+void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+#ifdef CONFIG_AEC62XX_TUNING
+	unsigned long flags;
+	byte reg54h = 0;
+
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
+
+	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+
+	__restore_flags(flags);	/* local CPU only */
+#endif /* CONFIG_AEC62XX_TUNING */
+	ide_setup_dma(hwif, dmabase, 8);
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ali14xx.c linux/drivers/ide/ali14xx.c
--- v2.3.99-pre5/linux/drivers/ide/ali14xx.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ali14xx.c	Thu Apr 13 22:54:26 2000
@@ -48,6 +48,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
@@ -118,7 +119,7 @@
 	byte param1, param2, param3, param4;
 	unsigned long flags;
 	ide_pio_data_t d;
-	int bus_speed = ide_system_bus_speed();
+	int bus_speed = system_bus_clock();
 
 	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c
--- v2.3.99-pre5/linux/drivers/ide/alim15x3.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/alim15x3.c	Thu Apr 13 22:54:26 2000
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
@@ -249,7 +250,7 @@
 	int s_time, a_time, c_time;
 	byte s_clc, a_clc, r_clc;
 	unsigned long flags;
-	int bus_speed = ide_system_bus_speed();
+	int bus_speed = system_bus_clock();
 	int port = hwif->index ? 0x5c : 0x58;
 	int portFIFO = hwif->channel ? 0x55 : 0x54;
 	byte cd_dma_fifo = 0;
@@ -409,14 +410,14 @@
 
 static byte ali15x3_can_ultra (ide_drive_t *drive)
 {
-#ifdef CONFIG_WDC_ALI15X3
+#ifndef CONFIG_WDC_ALI15X3
 	struct hd_driveid *id	= drive->id;
 #endif /* CONFIG_WDC_ALI15X3 */
 
 	if (m5229_revision <= 0x20) {
 		return 0;
 	} else if ((m5229_revision < 0xC2) &&
-#ifdef CONFIG_WDC_ALI15X3
+#ifndef CONFIG_WDC_ALI15X3
 		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
 		    (drive->media!=ide_disk))) {
 #else /* CONFIG_WDC_ALI15X3 */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/amd7409.c linux/drivers/ide/amd7409.c
--- v2.3.99-pre5/linux/drivers/ide/amd7409.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/amd7409.c	Thu Apr 13 22:54:26 2000
@@ -17,6 +17,7 @@
 #include <linux/hdreg.h>
 
 #include <linux/interrupt.h>
+#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/buddha.c linux/drivers/ide/buddha.c
--- v2.3.99-pre5/linux/drivers/ide/buddha.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/buddha.c	Thu Apr 13 22:54:26 2000
@@ -21,6 +21,7 @@
 #include <linux/hdreg.h>
 #include <linux/zorro.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/cmd640.c linux/drivers/ide/cmd640.c
--- v2.3.99-pre5/linux/drivers/ide/cmd640.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/cmd640.c	Thu Apr 13 22:54:26 2000
@@ -111,6 +111,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
@@ -595,7 +596,7 @@
 {
 	int setup_time, active_time, recovery_time, clock_time;
 	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-	int bus_speed = ide_system_bus_speed();
+	int bus_speed = system_bus_clock();
 
 	if (pio_mode > 5)
 		pio_mode = 5;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/cmd64x.c linux/drivers/ide/cmd64x.c
--- v2.3.99-pre5/linux/drivers/ide/cmd64x.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/cmd64x.c	Thu Apr 13 22:54:26 2000
@@ -19,8 +19,10 @@
 #include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
+
 #include "ide_modes.h"
 
 #ifndef SPLIT_BYTE
@@ -271,7 +273,7 @@
 	int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
 	byte recovery_count2, cycle_count;
 	int setup_count, active_count, recovery_count;
-	int bus_speed = ide_system_bus_speed();
+	int bus_speed = system_bus_clock();
 	/*byte b;*/
 	ide_pio_data_t  d;
 
@@ -645,6 +647,9 @@
 #endif
 	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
 	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
+#ifdef CONFIG_PPC
+	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
+#endif /* CONFIG_PPC */
 
 #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!cmd64x_proc) {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/cy82c693.c linux/drivers/ide/cy82c693.c
--- v2.3.99-pre5/linux/drivers/ide/cy82c693.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/cy82c693.c	Thu Apr 13 22:54:26 2000
@@ -49,6 +49,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
@@ -140,9 +141,8 @@
 static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
 {
 	int clk1, clk2;
-	int bus_speed;
+	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
 
-	bus_speed = ide_system_bus_speed();	/* get speed of PCI bus */
 	/* we don't check against CY82C693's min and max speed,
 	 * so you can play with the idebus=xx parameter
 	 */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/dtc2278.c linux/drivers/ide/dtc2278.c
--- v2.3.99-pre5/linux/drivers/ide/dtc2278.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/dtc2278.c	Thu Apr 13 22:54:26 2000
@@ -15,6 +15,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/falconide.c linux/drivers/ide/falconide.c
--- v2.3.99-pre5/linux/drivers/ide/falconide.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/falconide.c	Thu Apr 13 22:54:26 2000
@@ -14,6 +14,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/gayle.c linux/drivers/ide/gayle.c
--- v2.3.99-pre5/linux/drivers/ide/gayle.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/gayle.c	Thu Apr 13 22:54:26 2000
@@ -15,6 +15,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ht6560b.c linux/drivers/ide/ht6560b.c
--- v2.3.99-pre5/linux/drivers/ide/ht6560b.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ht6560b.c	Thu Apr 13 22:54:26 2000
@@ -47,6 +47,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
@@ -203,9 +204,10 @@
 
 static byte ht_pio2timings(ide_drive_t *drive, byte pio)
 {
-	int bus_speed, active_time, recovery_time;
+	int active_time, recovery_time;
 	int active_cycles, recovery_cycles;
 	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
 	
         if (pio) {
 		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
@@ -215,7 +217,6 @@
 		 *  actual cycle time for recovery and activity
 		 *  according system bus speed.
 		 */
-		bus_speed = ide_system_bus_speed();
 		active_time = ide_pio_timings[pio].active_time;
 		recovery_time = d.cycle_time 
 			- active_time
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/icside.c linux/drivers/ide/icside.c
--- v2.3.99-pre5/linux/drivers/ide/icside.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/icside.c	Thu Apr 13 22:54:26 2000
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/dma.h>
 #include <asm/ecard.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- v2.3.99-pre5/linux/drivers/ide/ide-cd.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-cd.c	Tue Apr 25 17:46:33 2000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998, 1999 Jens Axboe <axboe@image.dk>
+ * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
@@ -16,8 +16,8 @@
  * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI 
  * (SFF-8020i rev 2.6) standards. These documents can be obtained by 
  * anonymous ftp from:
- * ftp://fission.dt.wdc.com/pub/standards/SFF/specs/INF-8020.PDF
- * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r01.pdf
+ * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
+ * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
  *
  * Drives that deviate from these standards will be accomodated as much
  * as possible via compile time or command-line options.  Since I only have
@@ -272,10 +272,19 @@
  *			- Fixed a problem with WPI CDS-32X drive - it
  *			  failed the capabilities 
  *
+ * 4.57  Apr 7, 2000	- Fixed sense reporting.
+ *			- Fixed possible oops in ide_cdrom_get_last_session()
+ *			- Fix locking mania and make ide_cdrom_reset relock
+ *			- Stop spewing errors to log when magicdev polls with
+ *			  TEST_UNIT_READY on some drives.
+ *			- Various fixes from Tobias Ringstrom:
+ *			  tray if it was locked prior to the reset.
+ *			  - cdrom_read_capacity returns one frame too little.
+ *			  - Fix real capacity reporting.
  *
  *************************************************************************/
  
-#define IDECD_VERSION "4.56"
+#define IDECD_VERSION "4.57"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -314,11 +323,12 @@
 
 
 static
-void cdrom_analyze_sense_data (ide_drive_t *drive, struct request_sense *reqbuf,
-			       struct packet_command *failed_command)
+void cdrom_analyze_sense_data(ide_drive_t *drive,
+			      struct packet_command *failed_command,
+			      struct request_sense *sense)
 {
-	if (reqbuf->sense_key == NOT_READY ||
-	    reqbuf->sense_key == UNIT_ATTENTION) {
+	if (sense->sense_key == NOT_READY ||
+	    sense->sense_key == UNIT_ATTENTION) {
 		/* Make good and sure we've seen this potential media change.
 		   Some drives (i.e. Creative) fail to present the correct
 		   sense key in the error register. */
@@ -330,13 +340,14 @@
 		   uses this command to poll the drive, and we don't want
 		   to fill the syslog with useless errors. */
 		if (failed_command &&
-		    failed_command->c[0] == GPCMD_READ_SUBCHANNEL)
+		    (failed_command->c[0] == GPCMD_READ_SUBCHANNEL ||
+		     failed_command->c[0] == GPCMD_TEST_UNIT_READY))
 			return;
 	}
 
-	if (reqbuf->error_code == 0x70 && reqbuf->sense_key  == 0x02
-	 && ((reqbuf->asc      == 0x3a && reqbuf->ascq       == 0x00) ||
-	     (reqbuf->asc      == 0x04 && reqbuf->ascq       == 0x01)))
+	if (sense->error_code == 0x70 && sense->sense_key  == 0x02
+	 && ((sense->asc      == 0x3a && sense->ascq       == 0x00) ||
+	     (sense->asc      == 0x04 && sense->ascq       == 0x01)))
 	{
 		/*
 		 * Suppress the following errors:
@@ -353,30 +364,32 @@
 		char buf[80];
 
 		printk ("ATAPI device %s:\n", drive->name);
-		if (reqbuf->error_code==0x70)
+		if (sense->error_code==0x70)
 			printk("  Error: ");
-		else if (reqbuf->error_code==0x71)
+		else if (sense->error_code==0x71)
 			printk("  Deferred Error: ");
+		else if (sense->error_code == 0x7f)
+			printk("  Vendor-specific Error: ");
 		else
 			printk("  Unknown Error Type: ");
 
-		if ( reqbuf->sense_key < ARY_LEN (sense_key_texts))
-			s = sense_key_texts[reqbuf->sense_key];
+		if (sense->sense_key < ARY_LEN(sense_key_texts))
+			s = sense_key_texts[sense->sense_key];
 		else
 			s = "bad sense key!";
 
-		printk ("%s -- (Sense key=0x%02x)\n", s, reqbuf->sense_key);
+		printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
 
-		if (reqbuf->asc == 0x40) {
-			sprintf (buf, "Diagnostic failure on component 0x%02x",
-				 reqbuf->ascq);
+		if (sense->asc == 0x40) {
+			sprintf(buf, "Diagnostic failure on component 0x%02x",
+				 sense->ascq);
 			s = buf;
 		} else {
-			int lo=0, mid, hi=ARY_LEN (sense_data_texts);
-			unsigned long key = (reqbuf->sense_key << 16);
-			key |= (reqbuf->asc << 8);
-			if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) )
-				key |= reqbuf->ascq;
+			int lo = 0, mid, hi = ARY_LEN(sense_data_texts);
+			unsigned long key = (sense->sense_key << 16);
+			key |= (sense->asc << 8);
+			if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
+				key |= sense->ascq;
 			s = NULL;
 
 			while (hi > lo) {
@@ -394,14 +407,14 @@
 		}
 
 		if (s == NULL) {
-			if (reqbuf->asc > 0x80)
+			if (sense->asc > 0x80)
 				s = "(vendor-specific error)";
 			else
 				s = "(reserved error code)";
 		}
 
-		printk ("  %s -- (asc=0x%02x, ascq=0x%02x)\n",
-			s, reqbuf->asc, reqbuf->ascq);
+		printk("  %s -- (asc=0x%02x, ascq=0x%02x)\n",
+			s, sense->asc, sense->ascq);
 
 		if (failed_command != NULL) {
 
@@ -431,21 +444,21 @@
 		 * In the case of NOT_READY, if SKSV is set the drive can
 		 * give us nice ETA readings.
 		 */
-		if (reqbuf->sense_key == NOT_READY && (reqbuf->sks[0] & 0x80)) {
-			int progress = (reqbuf->sks[1] << 8 | reqbuf->sks[2]) * 100;
+		if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
+			int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
 			printk("  Command is %02d%% complete\n", progress / 0xffff);
 
 		}
 
-		if (reqbuf->sense_key == ILLEGAL_REQUEST &&
-		    (reqbuf->sks[0] & 0x80) != 0) {
-			printk ("  Error in %s byte %d",
-				(reqbuf->sks[0] & 0x40) != 0 ?
+		if (sense->sense_key == ILLEGAL_REQUEST &&
+		    (sense->sks[0] & 0x80) != 0) {
+			printk("  Error in %s byte %d",
+				(sense->sks[0] & 0x40) != 0 ?
 				"command packet" : "command data",
-				(reqbuf->sks[1] << 8) + reqbuf->sks[2]);
+				(sense->sks[1] << 8) + sense->sks[2]);
 
-			if ((reqbuf->sks[0] & 0x40) != 0)
-				printk (" bit %d", reqbuf->sks[0] & 0x07);
+			if ((sense->sks[0] & 0x40) != 0)
+				printk (" bit %d", sense->sks[0] & 0x07);
 
 			printk ("\n");
 		}
@@ -456,45 +469,43 @@
 	/* Suppress printing unit attention and `in progress of becoming ready'
 	   errors when we're not being verbose. */
 
-	if (reqbuf->sense_key == UNIT_ATTENTION ||
-	    (reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 ||
-						reqbuf->asc == 0x3a)))
+	if (sense->sense_key == UNIT_ATTENTION ||
+	    (sense->sense_key == NOT_READY && (sense->asc == 4 ||
+						sense->asc == 0x3a)))
 		return;
 
-	printk ("%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
+	printk("%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
 		drive->name,
-		reqbuf->error_code, reqbuf->sense_key,
-		reqbuf->asc, reqbuf->ascq);
+		sense->error_code, sense->sense_key,
+		sense->asc, sense->ascq);
 #endif /* not VERBOSE_IDE_CD_ERRORS */
 }
 
-static void cdrom_queue_request_sense (ide_drive_t *drive, 
-				       struct semaphore *sem,
-				       struct packet_command *failed_command)
+static void cdrom_queue_request_sense(ide_drive_t *drive, 
+				      struct semaphore *sem,
+				      struct request_sense *sense,
+				      struct packet_command *failed_command)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq;
-	struct packet_command *pc;
+	struct packet_command *pc = &info->request_sense_pc;
 
-	/* Make up a new request to retrieve sense information. */
-	pc = &info->request_sense_pc;
-	memset(pc, 0, sizeof (*pc));
+	if (sense == NULL)
+		sense = &info->sense_data;
 
+	memset(pc, 0, sizeof(struct packet_command));
 	pc->c[0] = GPCMD_REQUEST_SENSE;
-
-	/* just get the first 18 bytes of the sense info, there might not
-	 * be more available */
 	pc->c[4] = pc->buflen = 18;
-	pc->buffer = (char *)&info->sense_data;
-	pc->sense_data = (struct request_sense *)failed_command;
+	pc->buffer = (char *) sense;
+	pc->sense = (struct request_sense *) failed_command;
 
 	/* stuff the sense request in front of our current request */
 	rq = &info->request_sense_request;
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->cmd = REQUEST_SENSE_COMMAND;
-	rq->buffer = (char *)pc;
+	rq->buffer = (char *) pc;
 	rq->sem = sem;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 
@@ -503,11 +514,10 @@
 	struct request *rq = HWGROUP(drive)->rq;
 
 	if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) {
-		struct packet_command *pc = (struct packet_command *)
-			                      rq->buffer;
-		cdrom_analyze_sense_data (drive,
-			(struct request_sense *) (pc->buffer - pc->c[4]),
-			(struct packet_command *) pc->sense_data);
+		struct packet_command *pc = (struct packet_command *)rq->buffer;
+		cdrom_analyze_sense_data(drive,
+			(struct packet_command *) pc->sense,
+			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
 	if (rq->cmd == READ && !rq->current_nr_sectors)
 		uptodate = 1;
@@ -523,7 +533,7 @@
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	int stat, cmd, err, sense_key;
-	struct packet_command *pc = (struct packet_command *) rq->buffer;
+	struct packet_command *pc;
 	
 	/* Check for errors. */
 	stat = GET_STAT();
@@ -547,6 +557,7 @@
 			   from the drive (probably while trying
 			   to recover from a former error).  Just give up. */
 
+			pc = (struct packet_command *) rq->buffer;
 			pc->stat = 1;
 			cdrom_end_request (1, drive);
 			*startstop = ide_error (drive, "request sense failure", stat);
@@ -556,6 +567,7 @@
 			/* All other functions, except for READ. */
 
 			struct semaphore *sem = NULL;
+			pc = (struct packet_command *) rq->buffer;
 
 			/* Check for tray open. */
 			if (sense_key == NOT_READY) {
@@ -589,7 +601,8 @@
 			cdrom_end_request (1, drive);
 
 			if ((stat & ERR_STAT) != 0)
-				cdrom_queue_request_sense(drive, sem, pc);
+				cdrom_queue_request_sense(drive, sem, pc->sense,
+							  pc);
 		} else {
 			/* Handle errors from READ requests. */
 
@@ -628,7 +641,7 @@
 			/* If we got a CHECK_CONDITION status,
 			   queue a request sense command. */
 			if ((stat & ERR_STAT) != 0)
-				cdrom_queue_request_sense(drive, NULL, NULL);
+				cdrom_queue_request_sense(drive, NULL, NULL, NULL);
 		}
 	}
 
@@ -1062,11 +1075,11 @@
 	pc.c[0] = GPCMD_READ_10;
 	pc.c[7] = (nframes >> 8);
 	pc.c[8] = (nframes & 0xff);
-	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
+	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
 
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
-					      &cdrom_read_intr);
+	return cdrom_transfer_packet_command(drive, pc.c, sizeof(pc.c),
+					     &cdrom_read_intr);
 }
 
 
@@ -1178,7 +1191,8 @@
  */
 
 /* Forward declarations. */
-static int cdrom_lockdoor(ide_drive_t *drive, int lockflag);
+static int cdrom_lockdoor(ide_drive_t *drive, int lockflag,
+			  struct request_sense *sense);
 
 /* Interrupt routine for packet command completion. */
 static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
@@ -1186,11 +1200,8 @@
 	int ireason, len, stat, thislen;
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
-	struct cdrom_info *info = drive->driver_data;
 	ide_startstop_t startstop;
 
-	pc->sense_data = &info->sense_data;
-
 	/* Check for errors. */
 	if (cdrom_decode_status (&startstop, drive, 0, &stat))
 		return startstop;
@@ -1320,8 +1331,12 @@
 static
 int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc)
 {
-	int retries = 10;
+	struct request_sense sense;
 	struct request req;
+	int retries = 10;
+
+	if (pc->sense == NULL)
+		pc->sense = &sense;
 
 	/* Start of retry loop. */
 	do {
@@ -1337,7 +1352,7 @@
 			/* The request failed.  Retry if it was due to a unit
 			   attention status
 			   (usually means media was changed). */
-			struct request_sense *reqbuf = pc->sense_data;
+			struct request_sense *reqbuf = pc->sense;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
 				cdrom_saw_media_change (drive);
@@ -1358,24 +1373,7 @@
 	} while (pc->stat != 0 && retries >= 0);
 
 	/* Return an error if the command failed. */
-	if (pc->stat)
-		return -EIO;
-
-	/* The command succeeded.  If it was anything other than
-	   a request sense, eject, or door lock command,
-	   and we think that the door is presently unlocked, lock it
-	   again. (The door was probably unlocked via an explicit
-	   CDROMEJECT ioctl.) */
-	if (CDROM_STATE_FLAGS (drive)->door_locked == 0 &&
-	    (pc->c[0] != GPCMD_TEST_UNIT_READY &&
-	     pc->c[0] != GPCMD_REQUEST_SENSE &&
-	     pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL &&
-	     pc->c[0] != GPCMD_START_STOP_UNIT &&
-	     pc->c[0] != GPCMD_MODE_SENSE_10 &&
-	     pc->c[0] != GPCMD_MODE_SELECT_10)) {
-		(void) cdrom_lockdoor (drive, 1);
-	}
-	return 0;
+	return pc->stat ? -EIO : 0;
 }
 
 /****************************************************************************
@@ -1483,13 +1481,14 @@
 	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
 }
 
-static int cdrom_check_status (ide_drive_t  *drive)
+static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
 {
 	struct packet_command pc;
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
 
 	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.c[0] = GPCMD_TEST_UNIT_READY;
 
@@ -1506,24 +1505,26 @@
 
 /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
 static int
-cdrom_lockdoor(ide_drive_t *drive, int lockflag)
+cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
 {
-	struct request_sense *sense;
+	struct request_sense my_sense;
 	struct packet_command pc;
 	int stat;
 
+	if (sense == NULL)
+		sense = &my_sense;
+
 	/* If the drive cannot lock the door, just pretend. */
-	if (CDROM_CONFIG_FLAGS (drive)->no_doorlock)
+	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
 		stat = 0;
-	else {
+	} else {
 		memset(&pc, 0, sizeof(pc));
+		pc.sense = sense;
 		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		pc.c[4] = (lockflag != 0);
 		stat = cdrom_queue_packet_command (drive, &pc);
 	}
 
-	sense = pc.sense_data;
-
 	/* If we got an illegal field error, the drive
 	   probably cannot lock the door. */
 	if (stat != 0 &&
@@ -1548,7 +1549,8 @@
 
 /* Eject the disk if EJECTFLAG is 0.
    If EJECTFLAG is 1, try to reload the disk. */
-static int cdrom_eject(ide_drive_t *drive, int ejectflag)
+static int cdrom_eject(ide_drive_t *drive, int ejectflag,
+		       struct request_sense *sense)
 {
 	struct packet_command pc;
 
@@ -1560,13 +1562,15 @@
 		return 0;
 
 	memset(&pc, 0, sizeof (pc));
+	pc.sense = sense;
 
 	pc.c[0] = GPCMD_START_STOP_UNIT;
 	pc.c[4] = 0x02 + (ejectflag != 0);
 	return cdrom_queue_packet_command (drive, &pc);
 }
 
-static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity)
+static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity,
+			       struct request_sense *sense)
 {
 	struct {
 		__u32 lba;
@@ -1576,7 +1580,8 @@
 	int stat;
 	struct packet_command pc;
 
-	memset(&pc, 0, sizeof (pc));
+	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.c[0] = GPCMD_READ_CDVD_CAPACITY;
 	pc.buffer = (char *)&capbuf;
@@ -1584,17 +1589,19 @@
 
 	stat = cdrom_queue_packet_command(drive, &pc);
 	if (stat == 0)
-		*capacity = be32_to_cpu(capbuf.lba);
+		*capacity = 1 + be32_to_cpu(capbuf.lba);
 
 	return stat;
 }
 
 static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
-				int format, char *buf, int buflen)
+				int format, char *buf, int buflen,
+				struct request_sense *sense)
 {
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.buffer =  buf;
 	pc.buflen = buflen;
@@ -1612,12 +1619,11 @@
 
 
 /* Try to read the entire TOC for the disk into our internal buffer. */
-static int cdrom_read_toc (ide_drive_t *drive)
+static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
 {
 	int stat, ntracks, i;
 	struct cdrom_info *info = drive->driver_data;
 	struct atapi_toc *toc = info->toc;
-	int minor = drive->select.b.unit << PARTN_BITS;
 	struct {
 		struct atapi_toc_header hdr;
 		struct atapi_toc_entry  ent;
@@ -1637,13 +1643,13 @@
 	/* Check to see if the existing data is still valid.
 	   If it is, just return. */
 	if (CDROM_STATE_FLAGS (drive)->toc_valid)
-		(void) cdrom_check_status(drive);
+		(void) cdrom_check_status(drive, sense);
 
 	if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0;
 
 	/* First read just the header, so we know how long the TOC is. */
-	stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr,
-				    sizeof (struct atapi_toc_header));
+	stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
+				    sizeof(struct atapi_toc_header), sense);
 	if (stat) return stat;
 
 #if ! STANDARD_ATAPI
@@ -1658,10 +1664,11 @@
 	if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS;
 
 	/* Now read the whole schmeer. */
-	stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr,
-				    sizeof (struct atapi_toc_header) +
-				    (ntracks + 1) *
-				    sizeof (struct atapi_toc_entry));
+	stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0,
+				  (char *)&toc->hdr,
+				   sizeof(struct atapi_toc_header) +
+				   (ntracks + 1) *
+				   sizeof(struct atapi_toc_entry), sense);
 
 	if (stat && toc->hdr.first_track > 1) {
 		/* Cds with CDI tracks only don't have any TOC entries,
@@ -1674,11 +1681,12 @@
 		   the readable TOC is empty (CDI tracks are not included)
 		   and only holds the Leadout entry. Heiko Eißfeldt */
 		ntracks = 0;
-		stat = cdrom_read_tocentry (drive, CDROM_LEADOUT, 1,
-					    0, (char *)&toc->hdr,
-					    sizeof (struct atapi_toc_header) +
-					   (ntracks+1) *
-					    sizeof (struct atapi_toc_entry));
+		stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
+					   (char *)&toc->hdr,
+					   sizeof(struct atapi_toc_header) +
+					   (ntracks + 1) *
+					   sizeof(struct atapi_toc_entry),
+					   sense);
 		if (stat) {
 			return stat;
 		}
@@ -1722,8 +1730,8 @@
 	/* Read the multisession information. */
 	if (toc->hdr.first_track != CDROM_LEADOUT) {
 		/* Read the multisession information. */
-		stat = cdrom_read_tocentry (drive, 0, 1, 1,
-					   (char *)&ms_tmp, sizeof (ms_tmp));
+		stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
+					   sizeof(ms_tmp), sense);
 		if (stat) return stat;
 	} else {
 		ms_tmp.ent.addr.msf.minute = 0;
@@ -1749,45 +1757,23 @@
 				     (long *)&toc->capacity);
 	if (stat)
 #endif
-	stat = cdrom_read_capacity (drive, &toc->capacity);
+	stat = cdrom_read_capacity(drive, &toc->capacity, sense);
 	if (stat) toc->capacity = 0x1fffff;
 
-	/* for general /dev/cdrom like mounting, one big disc */
-	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
-	HWIF(drive)->gd->sizes[minor] = (toc->capacity * SECTORS_PER_FRAME) >>
-					(BLOCK_SIZE_BITS - 9);
-
 	/* Remember that we've read this stuff. */
 	CDROM_STATE_FLAGS (drive)->toc_valid = 1;
 
-	/* should be "if multisession", but it does no harm. */
-	if (ntracks == 1)
-		return 0;
-
-	/* setup each minor to respond to a session */
-	minor++;
-	i = toc->hdr.first_track;
-	while ((i <= ntracks) && ((minor & CD_PART_MASK) < CD_PART_MAX)) {
-		drive->part[minor & PARTN_MASK].start_sect = 0;
- 		drive->part[minor & PARTN_MASK].nr_sects =
-			(toc->ent[i].addr.lba *
-			SECTORS_PER_FRAME) << (BLOCK_SIZE_BITS - 9);
-		HWIF(drive)->gd->sizes[minor] = (toc->ent[i].addr.lba *
-			SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
-		i++;
-		minor++;
-	}
-
 	return 0;
 }
 
 
 static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
-				 int buflen)
+				 int buflen, struct request_sense *sense)
 {
 	struct packet_command pc;
 
 	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	pc.buffer = buf;
 	pc.buflen = buflen;
@@ -1802,10 +1788,12 @@
 
 /* ATAPI cdrom drives are free to select the speed you request or any slower
    rate :-( Requesting too fast a speed will _not_ produce an error. */
-static int cdrom_select_speed (ide_drive_t *drive, int speed)
+static int cdrom_select_speed(ide_drive_t *drive, int speed,
+			      struct request_sense *sense)
 {
 	struct packet_command pc;
 	memset(&pc, 0, sizeof(pc));
+	pc.sense = sense;
 
 	if (speed == 0)
 		speed = 0xffff; /* set to max */
@@ -1825,7 +1813,7 @@
 		pc.c[5] = speed & 0xff;
        }
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
@@ -1869,10 +1857,7 @@
 	pc.buffer = cgc->buffer;
 	pc.buflen = cgc->buflen;
 	cgc->stat = cdrom_queue_packet_command(drive, &pc);
-
-	/* There was an error, assign sense. */
-	if (cgc->stat)
-		cgc->sense = pc.sense_data;
+	cgc->sense = pc.sense;
 
 	return cgc->stat;
 }
@@ -1938,7 +1923,7 @@
 		struct atapi_toc *toc;
 
 		/* Make sure our saved TOC is valid. */
-		stat = cdrom_read_toc(drive);
+		stat = cdrom_read_toc(drive, NULL);
 		if (stat) return stat;
 
 		toc = info->toc;
@@ -1978,11 +1963,22 @@
 int ide_cdrom_reset (struct cdrom_device_info *cdi)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+	struct request_sense sense;
 	struct request req;
+	int ret;
 
 	ide_init_drive_cmd (&req);
 	req.cmd = RESET_DRIVE_COMMAND;
-	return ide_do_drive_cmd (drive, &req, ide_wait);
+	ret = ide_do_drive_cmd(drive, &req, ide_wait);
+
+	/*
+	 * A reset will unlock the door. If it was previously locked,
+	 * lock it again.
+	 */
+	if (CDROM_STATE_FLAGS(drive)->door_locked)
+		(void) cdrom_lockdoor(drive, 1, &sense);
+
+	return ret;
 }
 
 
@@ -1990,120 +1986,33 @@
 int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+	struct request_sense sense;
 
 	if (position) {
-		int stat = cdrom_lockdoor (drive, 0);
+		int stat = cdrom_lockdoor(drive, 0, &sense);
 		if (stat) return stat;
 	}
 
-	return cdrom_eject(drive, !position);
+	return cdrom_eject(drive, !position, &sense);
 }
 
 static
 int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	return cdrom_lockdoor (drive, lock);
-}
-
-#undef __ACER50__
-
-#ifdef __ACER50__
-/*
- * the buffer struct used by ide_cdrom_get_capabilities()
- */
-struct get_capabilities_buf {
-	char pad[8];
-	struct atapi_capabilities_page cap;	/* this is 4 bytes short of ATAPI standard */
-	char extra_cap[4];			/* Acer 50X needs the regulation size buffer */
-};
-
-static
-int ide_cdrom_get_capabilities (struct cdrom_device_info *cdi, struct get_capabilities_buf *buf)
-{
-	int stat, attempts = 3, buflen = sizeof(*buf);
-	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_generic_command cgc;
-
-	/*
-	 * Most drives don't care about the buffer size;
-	 * they return as much info as there's room for.
-	 * But some older drives (?) had trouble with the
-	 * standard size, preferring 4 bytes less.
-	 * And the modern Acer 50X rejects anything smaller
-	 * than the standard size.
-	 */
-	if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX")))
-		buflen -= sizeof(buf->extra_cap);	/* for all drives except Acer 50X */
-
-	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
-		stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
-		if (stat == 0) {
-			/*
-			 * The ACER/AOpen 24X cdrom has the speed
-			 * fields byte-swapped from the standard.
-			 */
-			if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) {
-				buf->cap.curspeed = ntohs(buf->cap.curspeed);
-				buf->cap.maxspeed = ntohs(buf->cap.maxspeed);
-			}
-			CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176;
-			CDROM_CONFIG_FLAGS(drive)->max_speed     = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176;
-			return 0;
-		}
-	} while (--attempts);
-	return stat;
+	return cdrom_lockdoor(drive, lock, NULL);
 }
-#endif /* __ACER50__ */
 
 static
 int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
 {
-#ifndef __ACER50__
-        int stat, attempts = 3;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_generic_command cgc;
-	struct {
-		char pad[8];
-		struct atapi_capabilities_page cap;
-	} buf;
-#else
+	struct request_sense sense;
 	int stat;
-	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_generic_command cgc;
-	struct get_capabilities_buf buf;
-#endif /* __ACER50__ */
 
-	if ((stat = cdrom_select_speed (drive, speed)) < 0)
+	if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0)
 		return stat;
 
-	init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
-
-#ifndef __ACER50__
-	/* Now with that done, update the speed fields */
-        do {    /* we seem to get stat=0x01,err=0x00 the first time (??) */
-                if (attempts-- <= 0)
-                        return 0;
-                stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
-        } while (stat);
-
-        /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-        if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-                CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
-                CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
-        } else {
-                CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(ntohs(buf.cap.curspeed) + (176/2)) / 176;
-                CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
-        }
-#else
-	if (ide_cdrom_get_capabilities(cdi,&buf))
-		return 0;
-#endif /* __ACER50__ */
-
         cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
         return 0;
 }
@@ -2112,19 +2021,18 @@
 int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_info *info = drive->driver_data;
 
 	if (slot_nr == CDSL_CURRENT) {
-		struct request_sense *sense = &info->sense_data;
-		int stat = cdrom_check_status(drive);
-		if (stat == 0 || sense->sense_key == UNIT_ATTENTION)
+		struct request_sense sense;
+		int stat = cdrom_check_status(drive, &sense);
+		if (stat == 0 || sense.sense_key == UNIT_ATTENTION)
 			return CDS_DISC_OK;
 
-		if (sense->sense_key == NOT_READY && sense->asc == 0x04 &&
-		    sense->ascq == 0x04)
+		if (sense.sense_key == NOT_READY && sense.asc == 0x04 &&
+		    sense.ascq == 0x04)
 			return CDS_DISC_OK;
 
-		if (sense->sense_key == NOT_READY) {
+		if (sense.sense_key == NOT_READY) {
 			/* ATAPI doesn't have anything that can help
 			   us decide whether the drive is really
 			   emtpy or the tray is just open. irk. */
@@ -2132,9 +2040,8 @@
 		}
 
 		return CDS_DRIVE_NOT_READY;
-	} else {
-		return -EINVAL;
 	}
+	return -EINVAL;
 }
 
 static
@@ -2144,8 +2051,14 @@
 	struct atapi_toc *toc;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct cdrom_info *info = drive->driver_data;
+	struct request_sense sense;
+	int ret;
 
 	toc = info->toc;
+	if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL)
+		if ((ret = cdrom_read_toc(drive, &sense)))
+			return ret;
+
 	ms_info->addr.lba = toc->last_session_lba;
 	ms_info->xa_flag = toc->xa_flag;
 
@@ -2161,7 +2074,7 @@
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
 /* get MCN */
-	if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf))))
+	if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
 		return stat;
 
 	memcpy (mcn_info->medium_catalog_number, mcnbuf+9,
@@ -2183,11 +2096,13 @@
 				       int slot_nr)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+	int retval;
 	
 	if (slot_nr == CDSL_CURRENT) {
-		(void) cdrom_check_status(drive);
+		(void) cdrom_check_status(drive, NULL);
+		retval = CDROM_STATE_FLAGS (drive)->media_changed;
 		CDROM_STATE_FLAGS (drive)->media_changed = 0;
-		return CDROM_STATE_FLAGS (drive)->media_changed;
+		return retval;
 	} else {
 		return -EINVAL;
 	}
@@ -2272,40 +2187,31 @@
 	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
 
-	devinfo->de = devfs_register (drive->de, "cd", 2, DEVFS_FL_DEFAULT,
-				      HWIF(drive)->major, minor,
-				      S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
-				      ide_fops, NULL);
+	devinfo->de = devfs_register(drive->de, "cd", 2, DEVFS_FL_DEFAULT,
+				     HWIF(drive)->major, minor,
+				     S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+				     ide_fops, NULL);
 
-	return register_cdrom (devinfo);
+	return register_cdrom(devinfo);
 }
 
+/*
+ * the buffer struct used by ide_cdrom_get_capabilities()
+ */
+struct get_capabilities_buf {
+	char pad[8];
+	struct atapi_capabilities_page cap;
+	char extra_cap[4];
+};
 
 static
-int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
-#ifndef __ACER50__
-	int stat, nslots = 1, attempts = 3;
 	struct cdrom_generic_command cgc;
-	struct {
-		char pad[8];
-		struct atapi_capabilities_page cap;
-	} buf;
-#else
-	int nslots = 1;
-	struct cdrom_generic_command cgc;
-	struct get_capabilities_buf buf;
-#endif /* __ACER50__ */
-
-	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
-		return nslots;
-	}
+	int stat, attempts = 3;
 
-	init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
 	/* we have to cheat a little here. the packet will eventually
 	 * be queued with ide_cdrom_packet(), which extracts the
 	 * drive from cdi->handle. Since this device hasn't been
@@ -2314,37 +2220,51 @@
 	 */
 	cdi->handle = (ide_drive_t *) drive;
 	cdi->ops = &ide_cdrom_dops;
-#ifndef __ACER50__
-	/* we seem to get stat=0x01,err=0x00 the first time (??) */
-	do {
-		if (attempts-- <= 0)
-			return 0;
+	init_cdrom_command(&cgc, cap, sizeof(*cap), CGC_DATA_UNKNOWN);
+	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
 		stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
-	} while (stat);
-#else
-	if (ide_cdrom_get_capabilities(cdi,&buf))
+		if (!stat)
+			break;
+	} while (--attempts);
+	return stat;
+}
+
+static
+int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+{
+	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_device_info *cdi = &info->devinfo;
+	struct atapi_capabilities_page cap;
+	int nslots = 1;
+
+	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
+		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
+		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
+		return nslots;
+	}
+
+	if (ide_cdrom_get_capabilities(drive, &cap))
 		return 0;
-#endif /* __ACER50__ */
 
-	if (buf.cap.lock == 0)
+	if (cap.lock == 0)
 		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
-	if (buf.cap.eject)
+	if (cap.eject)
 		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
-	if (buf.cap.cd_r_write)
+	if (cap.cd_r_write)
 		CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
-	if (buf.cap.cd_rw_write)
+	if (cap.cd_rw_write)
 		CDROM_CONFIG_FLAGS (drive)->cd_rw = 1;
-	if (buf.cap.test_write)
+	if (cap.test_write)
 		CDROM_CONFIG_FLAGS (drive)->test_write = 1;
-	if (buf.cap.dvd_ram_read || buf.cap.dvd_r_read || buf.cap.dvd_rom)
+	if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
 		CDROM_CONFIG_FLAGS (drive)->dvd = 1;
-	if (buf.cap.dvd_ram_write)
+	if (cap.dvd_ram_write)
 		CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
-	if (buf.cap.dvd_r_write)
+	if (cap.dvd_r_write)
 		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
-	if (buf.cap.audio_play)
+	if (cap.audio_play)
 		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
-	if (buf.cap.mechtype == 0)
+	if (cap.mechtype == 0)
 		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
 
 #if ! STANDARD_ATAPI
@@ -2355,28 +2275,26 @@
 
 	else
 #endif /* not STANDARD_ATAPI */
-	if (buf.cap.mechtype == mechtype_individual_changer ||
-	    buf.cap.mechtype == mechtype_cartridge_changer) {
+	if (cap.mechtype == mechtype_individual_changer ||
+	    cap.mechtype == mechtype_cartridge_changer) {
 		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
 			CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
 			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
 		}
 	}
 
-#ifndef __ACER50__
 	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
 	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
 		CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
+			(((unsigned int)cap.curspeed) + (176/2)) / 176;
 		CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
 	} else {
 		CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(ntohs(buf.cap.curspeed) + (176/2)) / 176;
+			(ntohs(cap.curspeed) + (176/2)) / 176;
 		CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+			(ntohs(cap.maxspeed) + (176/2)) / 176;
 	}
-#endif /* __ACER50__ */
 
 	/* don't print speed if the drive reported 0.
 	 */
@@ -2400,7 +2318,7 @@
         else 	
         	printk (" drive");
 
-	printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size));
+	printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
@@ -2601,6 +2519,37 @@
 }
 
 static
+void ide_cdrom_revalidate (ide_drive_t *drive)
+{
+	struct cdrom_info *info = drive->driver_data;
+	struct atapi_toc *toc;
+	int minor = drive->select.b.unit << PARTN_BITS;
+	struct request_sense sense;
+
+	cdrom_read_toc(drive, &sense);
+
+	if (!CDROM_STATE_FLAGS(drive)->toc_valid)
+		return;
+
+	toc = info->toc;
+
+	/* for general /dev/cdrom like mounting, one big disc */
+	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
+	HWIF(drive)->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
+
+	blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
+}
+
+static
+unsigned long ide_cdrom_capacity (ide_drive_t *drive)
+{
+	unsigned capacity;
+
+	capacity = cdrom_read_capacity(drive, &capacity, NULL);
+	return capacity ? 0 : capacity * SECTORS_PER_FRAME;
+}
+
+static
 int ide_cdrom_cleanup(ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
@@ -2635,13 +2584,14 @@
 	ide_cdrom_open,			/* open */
 	ide_cdrom_release,		/* release */
 	ide_cdrom_check_media_change,	/* media_change */
+	ide_cdrom_revalidate,		/* revalidate */
 	NULL,				/* pre_reset */
-	NULL,				/* capacity */
+	ide_cdrom_capacity,		/* capacity */
 	NULL,				/* special */
 	NULL				/* proc */
 };
 
-int ide_cdrom_init (void);
+int ide_cdrom_init(void);
 static ide_module_t ide_cdrom_module = {
 	IDE_DRIVER_MODULE,
 	ide_cdrom_init,
@@ -2670,7 +2620,7 @@
 }
 #endif /* MODULE */
  
-int ide_cdrom_init (void)
+int ide_cdrom_init(void)
 {
 	ide_drive_t *drive;
 	struct cdrom_info *info;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
--- v2.3.99-pre5/linux/drivers/ide/ide-cd.h	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-cd.h	Wed Apr 26 15:30:39 2000
@@ -10,6 +10,15 @@
 #include <linux/cdrom.h>
 #include <asm/byteorder.h>
 
+/*
+ * Apparently older drives have problems with filling out the entire
+ * mode_sense capability structure. Define this to 1 if your drive isn't
+ * probed correctly.
+ */
+#ifndef BROKEN_CAP_PAGE
+#define BROKEN_CAP_PAGE 0
+#endif
+
 /* Turn this on to have the driver print out the meanings of the
    ATAPI error codes.  This will use up additional kernel-space
    memory, though. */
@@ -43,6 +52,8 @@
 #define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
 #define SECTORS_BUFFER		(SECTOR_BUFFER_SIZE / SECTOR_SIZE)
 
+#define BLOCKS_PER_FRAME	(CD_FRAMESIZE / BLOCK_SIZE)
+
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 /* special command codes for strategy routine. */
@@ -103,7 +114,7 @@
 	char *buffer;
 	int buflen;
 	int stat;
-	struct request_sense *sense_data;
+	struct request_sense *sense;
 	unsigned char c[12];
 };
 
@@ -187,6 +198,7 @@
  * generic stuff now in the Mt. Fuji spec.
  */
 struct atapi_capabilities_page {
+	struct mode_page_header header;
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 parameters_saveable : 1;
 	__u8 reserved1           : 1;
@@ -398,9 +410,9 @@
 	unsigned short buffer_size;
 	/* Current speed (in kB/s). */
 	unsigned short curspeed;
-
-	/* Truncate the structure here, so we don't have headaches reading
-	   from older drives. */
+#if !BROKEN_CAP_PAGE
+	char pad[4];
+#endif
 };
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- v2.3.99-pre5/linux/drivers/ide/ide-disk.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/ide/ide-disk.c	Thu Apr 13 22:50:32 2000
@@ -512,6 +512,13 @@
 	return drive->removable;	/* if removable, always assume it was changed */
 }
 
+static void idedisk_revalidate (ide_drive_t *drive)
+{
+	grok_partitions(HWIF(drive)->gd, drive->select.b.unit,
+			1<<PARTN_BITS,
+			current_capacity(drive));
+}
+
 /*
  * Compute drive->capacity, the full capacity of the drive
  * Called with drive->id != NULL.
@@ -726,6 +733,7 @@
 	idedisk_open,		/* open */
 	idedisk_release,	/* release */
 	idedisk_media_change,	/* media_change */
+	idedisk_revalidate,	/* revalidate */
 	idedisk_pre_reset,	/* pre_reset */
 	idedisk_capacity,	/* capacity */
 	idedisk_special,	/* special */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- v2.3.99-pre5/linux/drivers/ide/ide-dma.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-dma.c	Thu Apr 13 22:54:26 2000
@@ -368,7 +368,13 @@
 		}
 	} else if ((id->field_valid & 4) &&
 		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
+		if ((id->dma_ultra >> 10) & 1) {
+			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
+		} else if ((id->dma_ultra >> 9) & 1) {
+			printk(", UDMA(25)");	/* UDMA BIOS-enabled! */
+		} else {
+			printk(", UDMA(16)");	/* UDMA BIOS-enabled! */
+		}
 	} else if (id->field_valid & 4) {
 		printk(", (U)DMA");	/* Can be BIOS-enabled! */
 	} else {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- v2.3.99-pre5/linux/drivers/ide/ide-floppy.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-floppy.c	Thu Apr 13 22:50:32 2000
@@ -1376,6 +1376,16 @@
 }
 
 /*
+ *	Revalidate the new media. Should set blk_size[]
+ */
+static void idefloppy_revalidate (ide_drive_t *drive)
+{
+	grok_partitions(HWIF(drive)->gd, drive->select.b.unit,
+			1<<PARTN_BITS,
+			current_capacity(drive));
+}
+
+/*
  *	Return the current floppy capacity to ide.c.
  */
 static unsigned long idefloppy_capacity (ide_drive_t *drive)
@@ -1604,6 +1614,7 @@
 	idefloppy_open,		/* open */
 	idefloppy_release,	/* release */
 	idefloppy_media_change,	/* media_change */
+	idefloppy_revalidate,	/* media_change */
 	NULL,			/* pre_reset */
 	idefloppy_capacity,	/* capacity */
 	NULL,			/* special */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- v2.3.99-pre5/linux/drivers/ide/ide-pci.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/ide/ide-pci.c	Thu Apr 13 22:54:26 2000
@@ -52,6 +52,8 @@
 #define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
 #define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
 #define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
+#define DEVID_AEC6260	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860})
+#define DEVID_AEC6260R	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860R})
 #define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
 #define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
 #define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
@@ -66,17 +68,20 @@
 
 #define	IDE_IGNORE	((void *)-1)
 
-#ifdef CONFIG_BLK_DEV_AEC6210
-extern unsigned int pci_init_aec6210(struct pci_dev *, const char *);
-extern void ide_init_aec6210(ide_hwif_t *);
-extern void ide_dmacapable_aec6210(ide_hwif_t *, unsigned long);
-#define PCI_AEC6210	&pci_init_aec6210
-#define INIT_AEC6210	&ide_init_aec6210
-#define DMA_AEC6210	&ide_dmacapable_aec6210
-#else
-#define PCI_AEC6210	NULL
-#define INIT_AEC6210	NULL
-#define DMA_AEC6210	NULL
+#ifdef CONFIG_BLK_DEV_AEC62XX
+extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
+extern unsigned int ata66_aec62xx(ide_hwif_t *);
+extern void ide_init_aec62xx(ide_hwif_t *);
+extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
+#define PCI_AEC62XX	&pci_init_aec62xx
+#define ATA66_AEC62XX	&ata66_aec62xx
+#define INIT_AEC62XX	&ide_init_aec62xx
+#define DMA_AEC62XX	&ide_dmacapable_aec62xx
+#else
+#define PCI_AEC62XX	NULL
+#define ATA66_AEC62XX	NULL
+#define INIT_AEC62XX	NULL
+#define DMA_AEC62XX	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_ALI15X3
@@ -318,7 +323,9 @@
 	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC6210,	NULL,		INIT_AEC6210,	DMA_AEC6210,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0 },
+	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
+	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
+	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
 	{DEVID_W82C105,	"W82C105",	NULL,		NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
 	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -344,6 +351,8 @@
 		case PCI_DEVICE_ID_PROMISE_20246:
 		case PCI_DEVICE_ID_PROMISE_20262:
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
 			return dev->irq;
 		default:
 			break;
@@ -592,6 +601,7 @@
 		}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X))
 			autodma = 0;
 		if (autodma)
@@ -599,6 +609,8 @@
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c
--- v2.3.99-pre5/linux/drivers/ide/ide-pnp.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-pnp.c	Thu Apr 13 22:54:26 2000
@@ -17,6 +17,8 @@
  */
 
 #include <linux/ide.h>
+#include <linux/init.h>
+
 #include <linux/isapnp.h>
 
 #ifndef PREPARE_FUNC
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- v2.3.99-pre5/linux/drivers/ide/ide-probe.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-probe.c	Thu Apr 13 22:54:26 2000
@@ -204,6 +204,10 @@
 		hd_status = IDE_STATUS_REG;
 	}
 
+	/* set features register for atapi identify command to be sure of reply */
+	if ((cmd == WIN_PIDENTIFY))
+		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
+
 #if CONFIG_BLK_DEV_PDC4030
 	if (HWIF(drive)->chipset == ide_pdc4030) {
 		/* DC4030 hosted drives need their own identify... */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c
--- v2.3.99-pre5/linux/drivers/ide/ide-proc.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-proc.c	Thu Apr 13 22:54:26 2000
@@ -73,10 +73,10 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifdef CONFIG_BLK_DEV_AEC6210
-extern byte aec6210_proc;
-int (*aec6210_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AEC6210 */
+#ifdef CONFIG_BLK_DEV_AEC62XX
+extern byte aec62xx_proc;
+int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_AEC62XX */
 #ifdef CONFIG_BLK_DEV_ALI15X3
 extern byte ali_proc;
 int (*ali_display_info)(char *, char **, off_t, int) = NULL;
@@ -801,10 +801,10 @@
 	create_proc_read_entry("drivers", 0, proc_ide_root,
 				proc_ide_read_drivers, NULL);
 
-#ifdef CONFIG_BLK_DEV_AEC6210
-	if ((aec6210_display_info) && (aec6210_proc))
-		create_proc_info_entry("aec6210", 0, proc_ide_root, aec6210_display_info);
-#endif /* CONFIG_BLK_DEV_AEC6210 */
+#ifdef CONFIG_BLK_DEV_AEC62XX
+	if ((aec62xx_display_info) && (aec62xx_proc))
+		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
+#endif /* CONFIG_BLK_DEV_AEC62XX */
 #ifdef CONFIG_BLK_DEV_ALI15X3
 	if ((ali_display_info) && (ali_proc))
 		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
@@ -853,10 +853,10 @@
 	 * Mmmm.. does this free up all resources,
 	 * or do we need to do a more proper cleanup here ??
 	 */
-#ifdef CONFIG_BLK_DEV_AEC6210
-	if ((aec6210_display_info) && (aec6210_proc))
-		remove_proc_entry("ide/aec6210",0);
-#endif /* CONFIG_BLK_DEV_AEC6210 */
+#ifdef CONFIG_BLK_DEV_AEC62XX
+	if ((aec62xx_display_info) && (aec62xx_proc))
+		remove_proc_entry("ide/aec62xx",0);
+#endif /* CONFIG_BLK_DEV_AEC62XX */
 #ifdef CONFIG_BLK_DEV_ALI15X3
 	if ((ali_display_info) && (ali_proc))
 		remove_proc_entry("ide/ali",0);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- v2.3.99-pre5/linux/drivers/ide/ide-tape.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide-tape.c	Thu Apr 13 22:50:32 2000
@@ -5900,6 +5900,7 @@
 	idetape_blkdev_open,	/* open */
 	idetape_blkdev_release,	/* release */
 	NULL,			/* media_change */
+	NULL,			/* revalidate */
 	idetape_pre_reset,	/* pre_reset */
 	NULL,			/* capacity */
 	NULL,			/* special */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.3.99-pre5/linux/drivers/ide/ide.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/ide/ide.c	Fri Apr 21 16:14:58 2000
@@ -343,7 +343,7 @@
 			system_bus_speed = idebus_parameter;	/* user supplied value */
 #ifdef CONFIG_PCI
 		else if (pci_present())
-			system_bus_speed = 40;	/* safe default value for PCI */
+			system_bus_speed = 33;	/* safe default value for PCI */
 #endif /* CONFIG_PCI */
 		else
 			system_bus_speed = 50;	/* safe default value for VESA and PCI */
@@ -1091,11 +1091,9 @@
 #endif
 	block    = rq->sector;
 	blockend = block + rq->nr_sectors;
-#if 0
+
 	if ((rq->cmd == READ || rq->cmd == WRITE) &&
-	    (drive->media == ide_disk || drive->media == ide_floppy))
-#endif
-	{
+	    (drive->media == ide_disk || drive->media == ide_floppy)) {
 		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
 			printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
 			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
@@ -1777,10 +1775,8 @@
 		drive->part[p].nr_sects   = 0;
 	};
 
-	grok_partitions(HWIF(drive)->gd, drive->select.b.unit,
-			(drive->media != ide_disk &&
-			 drive->media != ide_floppy) ? 1 : 1<<PARTN_BITS,
-				current_capacity(drive));
+	if (DRIVER(drive)->revalidate)
+		DRIVER(drive)->revalidate(drive);
 
 	drive->busy = 0;
 	wake_up(&drive->wqueue);
@@ -2095,7 +2091,9 @@
 	hwif->config_data	= old_hwif.config_data;
 	hwif->select_data	= old_hwif.select_data;
 	hwif->proc		= old_hwif.proc;
+#ifndef CONFIG_BLK_DEV_IDECS
 	hwif->irq		= old_hwif.irq;
+#endif /* CONFIG_BLK_DEV_IDECS */
 	hwif->major		= old_hwif.major;
 	hwif->chipset		= old_hwif.chipset;
 	hwif->autodma		= old_hwif.autodma;
@@ -2447,8 +2445,18 @@
  */
 void ide_delay_50ms (void)
 {
+#if 0
 	unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
 	while (0 < (signed long)(timeout - jiffies));
+#else
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/20);
+#endif
+}
+
+int system_bus_clock (void)
+{
+	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
 static int ide_ioctl (struct inode *inode, struct file *file,
@@ -3350,7 +3358,7 @@
 
 static unsigned long default_capacity (ide_drive_t *drive)
 {
-	return 0x7fffffff;	/* cdrom or tape */
+	return 0x7fffffff;
 }
 
 static ide_startstop_t default_special (ide_drive_t *drive)
@@ -3578,6 +3586,8 @@
 EXPORT_SYMBOL(get_info_ptr);
 EXPORT_SYMBOL(current_capacity);
 
+EXPORT_SYMBOL(system_bus_clock);
+
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
@@ -3589,7 +3599,7 @@
 	if (!banner_printed) {
 		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
 		ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL);
-		(void) ide_system_bus_speed();
+		system_bus_speed = ide_system_bus_speed();
 		banner_printed = 1;
 	}
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide_modes.h linux/drivers/ide/ide_modes.h
--- v2.3.99-pre5/linux/drivers/ide/ide_modes.h	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ide_modes.h	Wed Apr 26 15:30:39 2000
@@ -124,8 +124,11 @@
 	{ "QUANTUM LPS540A", 3 },
 	{ "QUANTUM LIGHTNING 540A", 3 },
 	{ "QUANTUM LIGHTNING 730A", 3 },
-	{ "QUANTUM FIREBALL", 3 }, /* For models 540/640/1080/1280 */
-				   /* 1080A works fine in mode4 with triton */
+
+        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_1080", 3 },
+        { "QUANTUM FIREBALL_1280", 3 },
 	{ NULL,	0 }
 };
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/macide.c linux/drivers/ide/macide.c
--- v2.3.99-pre5/linux/drivers/ide/macide.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/ide/macide.c	Thu Apr 13 22:54:26 2000
@@ -18,6 +18,7 @@
 #include <linux/hdreg.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/machw.h>
 #include <asm/macintosh.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ns87415.c linux/drivers/ide/ns87415.c
--- v2.3.99-pre5/linux/drivers/ide/ns87415.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/ns87415.c	Thu Apr 13 22:54:26 2000
@@ -20,6 +20,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/opti621.c linux/drivers/ide/opti621.c
--- v2.3.99-pre5/linux/drivers/ide/opti621.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/opti621.c	Thu Apr 13 22:54:26 2000
@@ -215,8 +215,9 @@
 static void compute_clocks(int pio, pio_clocks_t *clks)
 {
         if (pio != PIO_NOT_EXIST) {
-        	int adr_setup, data_pls, bus_speed;
-        	bus_speed = ide_system_bus_speed();
+        	int adr_setup, data_pls;
+		int bus_speed = system_bus_clock();
+
  	       	adr_setup = ide_pio_timings[pio].setup_time;
   	      	data_pls = ide_pio_timings[pio].active_time;
 	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- v2.3.99-pre5/linux/drivers/ide/pdc4030.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/ide/pdc4030.c	Thu Apr 13 22:54:26 2000
@@ -82,6 +82,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/piix.c linux/drivers/ide/piix.c
--- v2.3.99-pre5/linux/drivers/ide/piix.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/piix.c	Thu Apr 13 22:54:26 2000
@@ -61,6 +61,7 @@
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/qd6580.c linux/drivers/ide/qd6580.c
--- v2.3.99-pre5/linux/drivers/ide/qd6580.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/qd6580.c	Thu Apr 13 22:54:26 2000
@@ -20,6 +20,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/rapide.c linux/drivers/ide/rapide.c
--- v2.3.99-pre5/linux/drivers/ide/rapide.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/rapide.c	Thu Apr 13 22:54:26 2000
@@ -13,6 +13,7 @@
 #include <linux/blkdev.h>
 #include <linux/errno.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/ecard.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c
--- v2.3.99-pre5/linux/drivers/ide/rz1000.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/rz1000.c	Thu Apr 13 22:54:26 2000
@@ -28,6 +28,7 @@
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c
--- v2.3.99-pre5/linux/drivers/ide/sis5513.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/sis5513.c	Tue Apr 25 17:55:37 2000
@@ -170,7 +170,7 @@
 		     reg2, reg3);
 
 	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
-	p += sprintf(p, "Drvie 0:        Postwrite %s \t \t Postwrite %s\n",
+	p += sprintf(p, "Drive 0:        Postwrite %s \t \t Postwrite %s\n",
 		     (reg & 0x10) ? "Enabled" : "Disabled",
 		     (reg & 0x40) ? "Enabled" : "Disabled");
 	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
@@ -194,7 +194,7 @@
 
 
 	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
-	p += sprintf(p, "Drvie 1:        Postwrite %s \t \t Postwrite %s\n",
+	p += sprintf(p, "Drive 1:        Postwrite %s \t \t Postwrite %s\n",
 		     (reg & 0x20) ? "Enabled" : "Disabled",
 		     (reg & 0x80) ? "Enabled" : "Disabled");
 	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/umc8672.c linux/drivers/ide/umc8672.c
--- v2.3.99-pre5/linux/drivers/ide/umc8672.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/umc8672.c	Thu Apr 13 22:54:26 2000
@@ -48,6 +48,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c
--- v2.3.99-pre5/linux/drivers/ide/via82cxxx.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/ide/via82cxxx.c	Thu Apr 13 22:54:26 2000
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/via82cxxx.c	Version 0.08	Mar. 18, 2000
+ * linux/drivers/ide/via82cxxx.c	Version 0.09	Apr. 02, 2000
  *
  *  Copyright (C) 1998-99	Michel Aubry, Maintainer
  *  Copyright (C) 1999		Jeff Garzik, MVP4 Support
@@ -93,27 +93,127 @@
 
 #include <asm/io.h>
 
+#include "ide_modes.h"
+
 static struct pci_dev *host_dev = NULL;
 static struct pci_dev *isa_dev = NULL;
 
+struct chipset_bus_clock_list_entry {
+	byte	xfer_speed;
+
+	byte	chipset_settings_25;
+	byte	ultra_settings_25;
+	byte	chipset_settings_33;
+	byte	ultra_settings_33;
+	byte	chipset_settings_37;
+	byte	ultra_settings_37;
+	byte	chipset_settings_41;
+	byte	ultra_settings_41;
+};
+
+static struct chipset_bus_clock_list_entry * via82cxxx_table = NULL;
+
+struct chipset_bus_clock_list_entry via82cxxx_type_one [] = {
+		/* speed */	/* 25 */	/* 33 */	/* 37.5 */	/* 41.5 */	
+	{	XFER_UDMA_4,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00	},
+	{	XFER_UDMA_3,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00	},
+	{	XFER_UDMA_2,	0x60,	0x20,	0x60,	0x20,	0x60,	0x21,	0x00,	0x00	},
+	{	XFER_UDMA_1,	0x61,	0x20,	0x61,	0x20,	0x61,	0x21,	0x00,	0x00	},
+	{	XFER_UDMA_0,	0x62,	0x20,	0x62,	0x20,	0x62,	0x21,	0x00,	0x00	},
+
+	{	XFER_MW_DMA_2,	0x03,	0x20,	0x03,	0x20,	0x03,	0x21,	0x00,	0x00	},
+	{	XFER_MW_DMA_1,	0x03,	0x31,	0x03,	0x31,	0x03,	0x32,	0x00,	0x00	},
+	{	XFER_MW_DMA_0,	0x03,	0x31,	0x03,	0x31,	0x03,	0x32,	0x00,	0x00	},
+
+	{	XFER_PIO_4,	0x03,	0x20,	0x03,	0x20,	0x03,	0x21,	0x00,	0x00	},
+	{	XFER_PIO_3,	0x03,	0x31,	0x03,	0x31,	0x03,	0x32,	0x00,	0x00	},
+	{	XFER_PIO_2,	0x03,	0x65,	0x03,	0x65,	0x03,	0x76,	0x00,	0x00	},
+	{	XFER_PIO_1,	0x03,	0x65,	0x03,	0x65,	0x03,	0x76,	0x00,	0x00	},
+	{	XFER_PIO_0,	0x03,	0xA8,	0x03,	0xA8,	0x03,	0xA9,	0x00,	0x00	},
+	{	0,		0x03,	0xA8,	0x03,	0xA8,	0x03,	0xA9,	0x00,	0x00	}
+};
+
+struct chipset_bus_clock_list_entry via82cxxx_type_two [] = {
+		/* speed */	/* 25 */	/* 33 */	/* 37.5 */	/* 41.5 */
+	{	XFER_UDMA_4,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00	},
+	{	XFER_UDMA_3,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00	},
+	{	XFER_UDMA_2,	0xE0,	0x20,	0xE0,	0x20,	0xE1,	0x31,	0xE1,	0x32	},
+	{	XFER_UDMA_1,	0xE1,	0x20,	0xE1,	0x20,	0xE2,	0x31,	0xE2,	0x32	},
+	{	XFER_UDMA_0,	0xE2,	0x20,	0xE2,	0x20,	0xE2,	0x31,	0xE2,	0x32	},
+
+	{	XFER_MW_DMA_2,	0x03,	0x20,	0x03,	0x20,	0x03,	0x31,	0x03,	0x32	},
+	{	XFER_MW_DMA_1,	0x03,	0x31,	0x03,	0x31,	0x03,	0x42,	0x03,	0x53	},
+	{	XFER_MW_DMA_0,	0x03,	0x31,	0x03,	0x31,	0x03,	0x42,	0x03,	0x53	},
+
+	{	XFER_PIO_4,	0x03,	0x20,	0x03,	0x20,	0x03,	0x31,	0x03,	0x32	},
+	{	XFER_PIO_3,	0x03,	0x31,	0x03,	0x31,	0x03,	0x42,	0x03,	0x53	},
+	{	XFER_PIO_2,	0x03,	0x65,	0x03,	0x65,	0x03,	0x87,	0x03,	0xA8	},
+	{	XFER_PIO_1,	0x03,	0x65,	0x03,	0x65,	0x03,	0x87,	0x03,	0xA8	},
+	{	XFER_PIO_0,	0x03,	0xA8,	0x03,	0xA8,	0x03,	0xDB,	0x03,	0xFE	},
+	{	0,		0x03,	0xA8,	0x03,	0xA8,	0x03,	0xDB,	0x03,	0xFE	}
+};
+
+struct chipset_bus_clock_list_entry via82cxxx_type_three [] = {
+		/* speed */	/* 25 */	/* 33 */	/* 37.5 */	/* 41.5 */
+	{	XFER_UDMA_4,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00	},
+	{	XFER_UDMA_3,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00	},
+	{	XFER_UDMA_2,	0xE0,	0x20,	0xE0,	0x20,	0xE1,	0x31,	0xE1,	0x32	},
+	{	XFER_UDMA_1,	0xE1,	0x20,	0xE1,	0x20,	0xE2,	0x31,	0xE2,	0x32	},
+	{	XFER_UDMA_0,	0xE2,	0x20,	0xE2,	0x20,	0xE2,	0x31,	0xE2,	0x32	},
+
+	{	XFER_MW_DMA_2,	0x03,	0x20,	0x03,	0x20,	0x03,	0x31,	0x03,	0x32	},
+	{	XFER_MW_DMA_1,	0x03,	0x31,	0x03,	0x31,	0x03,	0x42,	0x03,	0x53	},
+	{	XFER_MW_DMA_0,	0x03,	0x31,	0x03,	0x31,	0x03,	0x42,	0x03,	0x53	},
+
+	{	XFER_PIO_4,	0x03,	0x20,	0x03,	0x20,	0x03,	0x31,	0x03,	0x32	},
+	{	XFER_PIO_3,	0x03,	0x31,	0x03,	0x31,	0x03,	0x42,	0x03,	0x53	},
+	{	XFER_PIO_2,	0x03,	0x65,	0x03,	0x65,	0x03,	0x87,	0x03,	0xA8	},
+	{	XFER_PIO_1,	0x03,	0x65,	0x03,	0x65,	0x03,	0x87,	0x03,	0xA8	},
+	{	XFER_PIO_0,	0x03,	0xA8,	0x03,	0xA8,	0x03,	0xDB,	0x03,	0xFE	},
+	{	0,		0x03,	0xA8,	0x03,	0xA8,	0x03,	0xDB,	0x03,	0xFE	}
+};
+
+struct chipset_bus_clock_list_entry via82cxxx_type_four [] = {
+		/* speed */	/* 25 */	/* 33 */	/* 37.5 */	/* 41.5 */
+	{	XFER_UDMA_4,	0x00,	0x00,	0xE0,	0x20,	0xE1,	0x31,	0x00,	0x00	},
+	{	XFER_UDMA_3,	0x00,	0x00,	0xE1,	0x20,	0xE2,	0x31,	0x00,	0x00	},
+	{	XFER_UDMA_2,	0x00,	0x00,	0xE2,	0x20,	0xE4,	0x31,	0x00,	0x00	},
+	{	XFER_UDMA_1,	0x00,	0x00,	0xE4,	0x20,	0xE6,	0x31,	0x00,	0x00	},
+	{	XFER_UDMA_0,	0x00,	0x00,	0xE6,	0x20,	0xE6,	0x31,	0x00,	0x00	},
+
+	{	XFER_MW_DMA_2,	0x00,	0x00,	0x03,	0x20,	0x03,	0x31,	0x00,	0x00	},
+	{	XFER_MW_DMA_1,	0x00,	0x00,	0x03,	0x31,	0x03,	0x42,	0x00,	0x00	},
+	{	XFER_MW_DMA_0,	0x00,	0x00,	0x03,	0x31,	0x03,	0x42,	0x00,	0x00	},
+
+	{	XFER_PIO_4,	0x00,	0x00,	0x03,	0x20,	0x03,	0x31,	0x00,	0x00	},
+	{	XFER_PIO_3,	0x00,	0x00,	0x03,	0x31,	0x03,	0x42,	0x00,	0x00	},
+	{	XFER_PIO_2,	0x00,	0x00,	0x03,	0x65,	0x03,	0x87,	0x00,	0x00	},
+	{	XFER_PIO_1,	0x00,	0x00,	0x03,	0x65,	0x03,	0x87,	0x00,	0x00	},
+	{	XFER_PIO_0,	0x00,	0x00,	0x03,	0xA8,	0x03,	0xDB,	0x00,	0x00	},
+	{	0,		0x00,	0x00,	0x03,	0xA8,	0x03,	0xDB,	0x00,	0x00	}
+};
+
 static const struct {
 	const char *name;
+	unsigned short vendor_id;
 	unsigned short host_id;
 } ApolloHostChipInfo[] = {
-	{ "VT 82C585 Apollo VP1/VPX",	PCI_DEVICE_ID_VIA_82C585, },
-	{ "VT 82C595 Apollo VP2",	PCI_DEVICE_ID_VIA_82C595, },
-	{ "VT 82C597 Apollo VP3",	PCI_DEVICE_ID_VIA_82C597_0, },
-	{ "VT 82C598 Apollo MVP3",	PCI_DEVICE_ID_VIA_82C598_0, },
-	{ "VT 82C598 Apollo MVP3",	PCI_DEVICE_ID_VIA_82C598_0, },
-	{ "VT 82C680 Apollo P6",	PCI_DEVICE_ID_VIA_82C680, },
-	{ "VT 82C691 Apollo Pro",	PCI_DEVICE_ID_VIA_82C691, },
-	{ "VT 82C693 Apollo Pro Plus",	PCI_DEVICE_ID_VIA_82C693, },
-	{ "Apollo MVP4",		PCI_DEVICE_ID_VIA_8501_0, },
-	{ "VT 8371",			PCI_DEVICE_ID_VIA_8371_0, },
-	{ "VT 8601",			PCI_DEVICE_ID_VIA_8601_0, },
+	{ "VT 82C585 Apollo VP1/VPX",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C585, },
+	{ "VT 82C595 Apollo VP2",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C595, },
+	{ "VT 82C597 Apollo VP3",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0, },
+	{ "VT 82C598 Apollo MVP3",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C598_0, },
+	{ "VT 82C598 Apollo MVP3",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C598_0, },
+	{ "VT 82C680 Apollo P6",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C680, },
+	{ "VT 82C691 Apollo Pro",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C691, },
+	{ "VT 82C693 Apollo Pro Plus",	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C693, },
+	{ "Apollo MVP4",		PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8501_0, },
+	{ "VT 8371",			PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_0, },
+	{ "VT 8601",			PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8601_0, },
+	{ "AMD IronGate",		PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_7006, },
 };
 
 #define NUM_APOLLO_ISA_CHIP_DEVICES	2
+#define VIA_FLAG_NULL			0x00000000
 #define VIA_FLAG_CHECK_REV		0x00000001
 #define VIA_FLAG_ATA_66			0x00000002
 
@@ -121,18 +221,20 @@
 	unsigned short host_id;
 	unsigned short isa_id;
 	unsigned int flags;
+	struct chipset_bus_clock_list_entry * chipset_table;
 } ApolloISAChipInfo[] = {
-	{ PCI_DEVICE_ID_VIA_82C585,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
-	{ PCI_DEVICE_ID_VIA_82C595,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
-	{ PCI_DEVICE_ID_VIA_82C597_0,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
-	{ PCI_DEVICE_ID_VIA_82C598_0,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
-	{ PCI_DEVICE_ID_VIA_82C598_0,	PCI_DEVICE_ID_VIA_82C596,	0 },
-	{ PCI_DEVICE_ID_VIA_82C680,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
-	{ PCI_DEVICE_ID_VIA_82C691,	PCI_DEVICE_ID_VIA_82C596,	VIA_FLAG_ATA_66 },
-	{ PCI_DEVICE_ID_VIA_82C693,	PCI_DEVICE_ID_VIA_82C596,	0 },
-	{ PCI_DEVICE_ID_VIA_8501_0,	PCI_DEVICE_ID_VIA_82C686,	VIA_FLAG_ATA_66 },
-	{ PCI_DEVICE_ID_VIA_8371_0,	PCI_DEVICE_ID_VIA_82C686,	VIA_FLAG_ATA_66 },
-	{ PCI_DEVICE_ID_VIA_8601_0,	PCI_DEVICE_ID_VIA_8231,		VIA_FLAG_ATA_66 },
+	{ PCI_DEVICE_ID_VIA_82C585,		PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV,	via82cxxx_type_one	},
+	{ PCI_DEVICE_ID_VIA_82C595,		PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV,	via82cxxx_type_one	},
+	{ PCI_DEVICE_ID_VIA_82C597_0,		PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV,	via82cxxx_type_one	},
+	{ PCI_DEVICE_ID_VIA_82C598_0,		PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV,	via82cxxx_type_one	},
+	{ PCI_DEVICE_ID_VIA_82C598_0,		PCI_DEVICE_ID_VIA_82C596,	VIA_FLAG_NULL,		via82cxxx_type_one	},
+	{ PCI_DEVICE_ID_VIA_82C680,		PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV,	via82cxxx_type_one	},
+	{ PCI_DEVICE_ID_VIA_82C691,		PCI_DEVICE_ID_VIA_82C596,	VIA_FLAG_ATA_66,	via82cxxx_type_two	},
+	{ PCI_DEVICE_ID_VIA_82C693,		PCI_DEVICE_ID_VIA_82C596,	VIA_FLAG_NULL,		via82cxxx_type_one	},
+	{ PCI_DEVICE_ID_VIA_8501_0,		PCI_DEVICE_ID_VIA_82C686,	VIA_FLAG_ATA_66,	via82cxxx_type_two	},
+	{ PCI_DEVICE_ID_VIA_8371_0,		PCI_DEVICE_ID_VIA_82C686,	VIA_FLAG_ATA_66,	via82cxxx_type_two	},
+	{ PCI_DEVICE_ID_VIA_8601_0,		PCI_DEVICE_ID_VIA_8231,		VIA_FLAG_ATA_66,	via82cxxx_type_two	},
+	{ PCI_DEVICE_ID_AMD_FE_GATE_7006,	PCI_DEVICE_ID_VIA_82C686,	VIA_FLAG_ATA_66,	via82cxxx_type_two	},
 };
 
 #define arraysize(x)	(sizeof(x)/sizeof(*(x)))
@@ -515,69 +617,40 @@
 }
 
 #ifdef CONFIG_VIA82CXXX_TUNING
+static byte pci_bus_clock_list (byte speed, int ide_clock, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			switch(ide_clock) {
+				case 25: return chipset_table->chipset_settings_25;
+				case 33: return chipset_table->chipset_settings_33;
+				case 37: return chipset_table->chipset_settings_37;
+				case 41: return chipset_table->chipset_settings_41;
+				default: break;
+			}
+		}
+	return 0x00;
+}
 
-struct chipset_bus_clock_list_entry {
-	unsigned short	bus_speed;
-	byte		xfer_speed;
-	byte		chipset_settings;
-};
-
-PCI_DEVICE_ID_VIA_82C586_1
-PCI_DEVICE_ID_VIA_82C596
-PCI_DEVICE_ID_VIA_82C686
-PCI_DEVICE_ID_VIA_8231
-
-PCI_DEVICE_ID_VIA_82C586_1	TYPE_1
-PCI_DEVICE_ID_VIA_82C596	TYPE_2
-PCI_DEVICE_ID_VIA_82C686	TYPE_2
-PCI_DEVICE_ID_VIA_82C596	TYPE_3
-PCI_DEVICE_ID_VIA_82C686	TYPE_3
-PCI_DEVICE_ID_VIA_8231		TYPE_4
-
-struct chipset_bus_clock_list_entry ultra_33_base [] = {
-{ TYPE_1,25,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 },
-{ TYPE_1,33,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 },
-{ TYPE_1,37,0x00,0x00,0x60,0x61,0x62,0x03,0x21,0x32,0x76,0x76,0xA9 },
-{ TYPE_2,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
-{ TYPE_2,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
-{ TYPE_2,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB },
-{ TYPE_2,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE },
-{ TYPE_3,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
-{ TYPE_3,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
-{ TYPE_3,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB },
-{ TYPE_3,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE },
-{ TYPE_4,0,0,0,0,0,0,0,0,0,0,0,0 },
-{ 0,0,0,0,0,0,0,0,0,0,0,0,0 }
-};
-
-struct chipset_bus_clock_list_entry timing_66_base [] = {
-	{ 37,	XFER_PIO_4,	0x21 },
-	{ 37,	XFER_PIO_3,	0x32 },
-	{ 37,	XFER_PIO_2,	0x76 },
-	{ 37,	XFER_PIO_1,	0x76 },
-	{ 37,	XFER_PIO_0,	0xA9 },
-	{ ANY,	XFER_PIO_4,	0x20 },
-	{ ANY,	XFER_PIO_3,	0x31 },
-	{ ANY,	XFER_PIO_2,	0x65 },
-	{ ANY,	XFER_PIO_1,	0x65 },
-	{ ANY,	XFER_PIO_0,	0xA8 },
-};
-
-static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+static byte pci_bus_clock_list_ultra (byte speed, int ide_clock, struct chipset_bus_clock_list_entry * chipset_table)
 {
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->chipset_settings;
+			switch(ide_clock) {
+				case 25: return chipset_table->ultra_settings_25;
+				case 33: return chipset_table->ultra_settings_33;
+				case 37: return chipset_table->ultra_settings_37;
+				case 41: return chipset_table->ultra_settings_41;
+				default: break;
+			}
 		}
-	return 0x01208585;
+	return 0x00;
 }
 
 static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long dma_base	= hwif->dma_base;
 	byte unit		= (drive->select.b.unit & 0x01);
 	int drive_number	= ((hwif->channel ? 2 : 0) + unit);
 
@@ -587,43 +660,23 @@
 	byte ultra		= 0x00;
 	int			err;
 
-	int bus_speed		= ide_system_bus_speed();
+	int bus_speed		= system_bus_clock();
 
 	switch(drive_number) {
-		case 0: ata2_pci = 0x48; ata3_pci = 0x50; break;
-		case 1: ata2_pci = 0x49; ata3_pci = 0x51; break;
-		case 2: ata2_pci = 0x4a; ata3_pci = 0x52; break;
-		case 3: ata2_pci = 0x4b; ata3_pci = 0x53; break;
+		case 0: ata2_pci = 0x4b; ata3_pci = 0x53; break;
+		case 1: ata2_pci = 0x4a; ata3_pci = 0x52; break;
+		case 2: ata2_pci = 0x49; ata3_pci = 0x51; break;
+		case 3: ata2_pci = 0x48; ata3_pci = 0x50; break;
 		default:
 			return -1;
 	}
 
 	pci_read_config_byte(dev, ata2_pci, &timing);
-	pci_read_config_byte(dev, ata3_pci, &ultra);
-
-	switch(speed) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			break;
-	}
-
+	timing = pci_bus_clock_list(speed, bus_speed, via82cxxx_table);
 	pci_write_config_byte(dev, ata2_pci, timing);
+
+	pci_read_config_byte(dev, ata3_pci, &ultra);
+	ultra = pci_bus_clock_list_ultra(speed, bus_speed, via82cxxx_table);
 	pci_write_config_byte(dev, ata3_pci, ultra);
 
 	err = ide_config_drive_speed(drive, speed);
@@ -830,6 +883,8 @@
 
 			if (ata33 | ata66)
 				printk(" Chipset Core ATA-%s", ata66 ? "66" : "33");
+
+			via82cxxx_table = ApolloISAChipInfo[j].chipset_table;
 		}
 		printk("\n");
 	}
@@ -847,8 +902,11 @@
 
 unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif)
 {
-	/* (Jeff Garzik) FIXME!!! for MVP4 */
-	return 0;
+	byte ata66	= 0;
+	byte ata66reg	= hwif->channel ? 0x50 : 0x52;
+	pci_read_config_byte(hwif->pci_dev, ata66reg, &ata66);
+
+	return ((ata66 & 0x04) ? 1 : 0);
 }
 
 void __init ide_init_via82cxxx (ide_hwif_t *hwif)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1dma.c	Mon Mar 27 08:08:24 2000
+++ linux/drivers/isdn/avmb1/b1dma.c	Thu Apr 13 09:03:03 2000
@@ -1,11 +1,14 @@
 /*
- * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil Exp $
+ * $Id: b1dma.c,v 1.4 2000/04/03 16:38:05 calle Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1dma.c,v $
+ * Revision 1.4  2000/04/03 16:38:05  calle
+ * made suppress_pollack static.
+ *
  * Revision 1.3  2000/02/26 01:00:53  keil
  * changes from 2.3.47
  *
@@ -34,13 +37,13 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.4 $";
 
 /* ------------------------------------------------------------- */
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 
-int suppress_pollack = 0;
+static int suppress_pollack = 0;
 MODULE_PARM(suppress_pollack, "0-1i");
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1isa.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/avmb1/b1isa.c	Thu Apr 13 09:03:03 2000
@@ -1,11 +1,15 @@
 /*
- * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 calle Exp $
+ * $Id: b1isa.c,v 1.8 2000/04/03 13:29:24 calle Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1isa.c,v $
+ * Revision 1.8  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.7  2000/02/02 18:36:03  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -69,7 +73,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.8 $";
 
 /* ------------------------------------------------------------- */
 
@@ -265,6 +269,9 @@
 {
 	struct capi_driver *driver = &b1isa_driver;
 	char *p;
+	int retval = 0;
+
+	MOD_INC_USE_COUNT;
 
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
@@ -279,9 +286,10 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
-		return -EIO;
+		retval = -EIO;
 	}
-	return 0;
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pci.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/avmb1/b1pci.c	Thu Apr 13 09:03:03 2000
@@ -1,11 +1,15 @@
 /*
- * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $
+ * $Id: b1pci.c,v 1.21 2000/04/03 13:29:24 calle Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pci.c,v $
+ * Revision 1.21  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.20  2000/02/02 18:36:03  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -75,7 +79,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20 $";
+static char *revision = "$Revision: 1.21 $";
 
 /* ------------------------------------------------------------- */
 
@@ -509,6 +513,8 @@
 	char *p;
 	int retval;
 
+	MOD_INC_USE_COUNT;
+
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
 		p = strchr(driver->revision, '$');
@@ -522,6 +528,7 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -534,6 +541,7 @@
     		detach_capi_driver(driver);
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driverv4->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 #endif
@@ -545,6 +553,7 @@
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
     		detach_capi_driver(driverv4);
 #endif
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -554,6 +563,7 @@
 #ifdef MODULE
 			cleanup_module();
 #endif
+			MOD_DEC_USE_COUNT;
 			return retval;
 		}
 		ncards++;
@@ -561,12 +571,15 @@
 	if (ncards) {
 		printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n",
 				driver->name, ncards);
+		MOD_DEC_USE_COUNT;
 		return 0;
 	}
 	printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -ESRCH;
 #else
 	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -EIO;
 #endif
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pcmcia.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/avmb1/b1pcmcia.c	Thu Apr 13 17:06:00 2000
@@ -1,11 +1,15 @@
 /*
- * $Id: b1pcmcia.c,v 1.8 2000/03/06 18:00:23 calle Exp $
+ * $Id: b1pcmcia.c,v 1.9 2000/04/03 13:29:24 calle Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pcmcia.c,v $
+ * Revision 1.9  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.8  2000/03/06 18:00:23  calle
  * - Middleware extention now working with 2.3.49 (capifs).
  * - Fixed typos in debug section of capi.c
@@ -75,7 +79,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.8 $";
+static char *revision = "$Revision: 1.9 $";
 
 /* ------------------------------------------------------------- */
 
@@ -301,6 +305,9 @@
 {
 	struct capi_driver *driver = &b1pcmcia_driver;
 	char *p;
+	int retval = 0;
+
+	MOD_INC_USE_COUNT;
 
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
@@ -315,9 +322,10 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
-		return -EIO;
+		retval = -EIO;
 	}
-	return 0;
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/c4.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/avmb1/c4.c	Thu Apr 13 09:03:03 2000
@@ -1,11 +1,18 @@
 /*
- * $Id: c4.c,v 1.6 2000/03/17 12:21:08 calle Exp $
+ * $Id: c4.c,v 1.8 2000/04/03 16:38:05 calle Exp $
  * 
  * Module for AVM C4 card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: c4.c,v $
+ * Revision 1.8  2000/04/03 16:38:05  calle
+ * made suppress_pollack static.
+ *
+ * Revision 1.7  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.6  2000/03/17 12:21:08  calle
  * send patchvalues now working.
  *
@@ -46,7 +53,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.6 $";
+static char *revision = "$Revision: 1.8 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
@@ -71,7 +78,7 @@
 
 /* ------------------------------------------------------------- */
 
-int suppress_pollack = 0;
+static int suppress_pollack = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 
@@ -1294,6 +1301,8 @@
 	char *p;
 	int retval;
 
+	MOD_INC_USE_COUNT;
+
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
 		p = strchr(driver->revision, '$');
@@ -1307,6 +1316,7 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -1314,6 +1324,7 @@
 	if (!pci_present()) {
 		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
     		detach_capi_driver(driver);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -1337,6 +1348,7 @@
 #ifdef MODULE
 			cleanup_module();
 #endif
+			MOD_DEC_USE_COUNT;
 			return retval;
 		}
 		ncards++;
@@ -1344,12 +1356,15 @@
 	if (ncards) {
 		printk(KERN_INFO "%s: %d C4 card(s) detected\n",
 				driver->name, ncards);
+		MOD_DEC_USE_COUNT;
 		return 0;
 	}
 	printk(KERN_ERR "%s: NO C4 card detected\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -ESRCH;
 #else
 	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -EIO;
 #endif
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/capi.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/avmb1/capi.c	Fri Apr 21 15:17:57 2000
@@ -1,11 +1,15 @@
 /*
- * $Id: capi.c,v 1.30 2000/03/19 12:31:36 calle Exp $
+ * $Id: capi.c,v 1.31 2000/04/03 13:29:24 calle Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capi.c,v $
+ * Revision 1.31  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.30  2000/03/19 12:31:36  calle
  * PPP over CAPI raw driver disabled for now, ppp_generic has been changed.
  *
@@ -189,7 +193,7 @@
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 #include <linux/slab.h>
 
-static char *revision = "$Revision: 1.30 $";
+static char *revision = "$Revision: 1.31 $";
 
 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
 
@@ -362,12 +366,13 @@
 	struct capiminor *mp, **pp;
         unsigned int minor = 0;
 
+	MOD_INC_USE_COUNT;
 	mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC);
 	if (!mp) {
+		MOD_DEC_USE_COUNT;
 		printk(KERN_ERR "capi: can't alloc capiminor\n");
 		return 0;
 	}
-	MOD_INC_USE_COUNT;
 #ifdef _DEBUG_REFCOUNT
 	printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(THIS_MODULE));
 #endif
@@ -1835,7 +1840,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/capidrv.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/avmb1/capidrv.c	Thu Apr 13 09:03:03 2000
@@ -1,11 +1,21 @@
 /*
- * $Id: capidrv.c,v 1.30 2000/03/03 15:50:42 calle Exp $
+ * $Id: capidrv.c,v 1.32 2000/04/07 15:19:58 calle Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.c,v $
+ * Revision 1.32  2000/04/07 15:19:58  calle
+ * remove warnings
+ *
+ * Revision 1.31  2000/04/06 15:01:25  calle
+ * Bugfix: crash in capidrv.c when reseting a capi controller.
+ * - changed code order on remove of controller.
+ * - using tq_schedule for notifier in kcapi.c.
+ * - now using spin_lock_irqsave() and spin_unlock_irqrestore().
+ * strange: sometimes even MP hang on unload of isdn.o ...
+ *
  * Revision 1.30  2000/03/03 15:50:42  calle
  * - kernel CAPI:
  *   - Changed parameter "param" in capi_signal from __u32 to void *.
@@ -182,8 +192,8 @@
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.30 $";
-int debugmode = 0;
+static char *revision = "$Revision: 1.32 $";
+static int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 MODULE_PARM(debugmode, "i");
@@ -291,6 +301,7 @@
 /* -------- data definitions ----------------------------------------- */
 
 static capidrv_data global;
+static spinlock_t global_lock = SPIN_LOCK_UNLOCKED;
 static struct capi_interface *capifuncs;
 
 static void handle_dtrace_data(capidrv_contr *card,
@@ -450,33 +461,27 @@
 
 static inline capidrv_contr *findcontrbydriverid(int driverid)
 {
-	capidrv_contr *p = global.contr_list;
-    	long flags;
+    	unsigned long flags;
+	capidrv_contr *p;
 
-        save_flags(flags);
-        cli();
-	while (p) {
+	spin_lock_irqsave(&global_lock, flags);
+	for (p = global.contr_list; p; p = p->next)
 		if (p->myid == driverid)
 			break;
-		p = p->next;
-	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&global_lock, flags);
 	return p;
 }
 
 static capidrv_contr *findcontrbynumber(__u32 contr)
 {
+	unsigned long flags;
 	capidrv_contr *p = global.contr_list;
-	long flags;
 
-	save_flags(flags);
-	cli();
-	while (p) {
+	spin_lock_irqsave(&global_lock, flags);
+	for (p = global.contr_list; p; p = p->next)
 		if (p->contrnr == contr)
 			break;
-		p = p->next;
-	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&global_lock, flags);
 	return p;
 }
 
@@ -1564,47 +1569,41 @@
 static void handle_dtrace_data(capidrv_contr *card,
 			     int send, int level2, __u8 *data, __u16 len)
 {
-    long flags;
-    __u8 *p, *end;
-    isdn_ctrl cmd;
+    	__u8 *p, *end;
+    	isdn_ctrl cmd;
 
-    if (!len) {
-       printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
+    	if (!len) {
+		printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
 				card->contrnr, len);
-       return;
-    }
-
-    save_flags(flags);
-    cli();
-
-    if (level2) {
-        PUTBYTE_TO_STATUS(card, 'D');
-        PUTBYTE_TO_STATUS(card, '2');
-        PUTBYTE_TO_STATUS(card, send ? '>' : '<');
-        PUTBYTE_TO_STATUS(card, ':');
-    } else {
-        PUTBYTE_TO_STATUS(card, 'D');
-        PUTBYTE_TO_STATUS(card, '3');
-        PUTBYTE_TO_STATUS(card, send ? '>' : '<');
-        PUTBYTE_TO_STATUS(card, ':');
-    }
+		return;
+	}
 
-    for (p = data, end = data+len; p < end; p++) {
-       __u8 w;
-       PUTBYTE_TO_STATUS(card, ' ');
-       w = (*p >> 4) & 0xf;
-       PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
-       w = *p & 0xf;
-       PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
-    }
-    PUTBYTE_TO_STATUS(card, '\n');
+	if (level2) {
+		PUTBYTE_TO_STATUS(card, 'D');
+		PUTBYTE_TO_STATUS(card, '2');
+        	PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+        	PUTBYTE_TO_STATUS(card, ':');
+	} else {
+        	PUTBYTE_TO_STATUS(card, 'D');
+        	PUTBYTE_TO_STATUS(card, '3');
+        	PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+        	PUTBYTE_TO_STATUS(card, ':');
+    	}
+
+	for (p = data, end = data+len; p < end; p++) {
+		__u8 w;
+		PUTBYTE_TO_STATUS(card, ' ');
+		w = (*p >> 4) & 0xf;
+		PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+		w = *p & 0xf;
+		PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+	}
+	PUTBYTE_TO_STATUS(card, '\n');
 
-    restore_flags(flags);
-    
-    cmd.command = ISDN_STAT_STAVAIL;
-    cmd.driver = card->myid;
-    cmd.arg = len*3+5;
-    card->interface.statcallb(&cmd);
+	cmd.command = ISDN_STAT_STAVAIL;
+	cmd.driver = card->myid;
+	cmd.arg = len*3+5;
+	card->interface.statcallb(&cmd);
 }
 
 /* ------------------------------------------------------------------- */
@@ -2009,8 +2008,8 @@
 		return capidrv_command(c, card);
 
 	printk(KERN_ERR
-	     "capidrv-%d: if_command %d called with invalid driverId %d!\n",
-	       card->contrnr, c->command, c->driver);
+	     "capidrv: if_command %d called with invalid driverId %d!\n",
+						c->command, c->driver);
 	return -ENODEV;
 }
 
@@ -2297,12 +2296,11 @@
 	}
 	card->myid = card->interface.channels;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&global_lock, flags);
 	card->next = global.contr_list;
 	global.contr_list = card;
 	global.ncontr++;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&global_lock, flags);
 
 	memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
 	for (i = 0; i < card->nbchan; i++) {
@@ -2333,25 +2331,22 @@
 static int capidrv_delcontr(__u16 contr)
 {
 	capidrv_contr **pp, *card;
+	unsigned long flags;
 	isdn_ctrl cmd;
-	long flags;
-	int i;
 
-	save_flags(flags);
-	cli();
-	for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
-		if ((*pp)->contrnr == contr)
+	spin_lock_irqsave(&global_lock, flags);
+	for (card = global.contr_list; card; card = card->next) {
+		if (card->contrnr == contr)
 			break;
 	}
-	if (!*pp) {
-		restore_flags(flags);
+	if (!card) {
+		spin_unlock_irqrestore(&global_lock, flags);
 		printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
 		return -1;
 	}
-	card = *pp;
-	*pp = (*pp)->next;
-	global.ncontr--;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&global_lock, flags);
+
+	del_timer(&card->listentimer);
 
 	if (debugmode)
 		printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
@@ -2361,28 +2356,51 @@
 	cmd.driver = card->myid;
 	card->interface.statcallb(&cmd);
 
-	for (i = 0; i < card->nbchan; i++) {
+	while (card->nbchan) {
 
 		cmd.command = ISDN_STAT_DISCH;
 		cmd.driver = card->myid;
-		cmd.arg = i;
+		cmd.arg = card->nbchan-1;
 	        cmd.parm.num[0] = 0;
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
+					card->contrnr, card->myid, cmd.arg);
 		card->interface.statcallb(&cmd);
 
-		if (card->bchans[i].nccip)
-			free_ncci(card, card->bchans[i].nccip);
-		if (card->bchans[i].plcip)
-			free_plci(card, card->bchans[i].plcip);
+		if (card->bchans[card->nbchan-1].nccip)
+			free_ncci(card, card->bchans[card->nbchan-1].nccip);
+		if (card->bchans[card->nbchan-1].plcip)
+			free_plci(card, card->bchans[card->nbchan-1].plcip);
 		if (card->plci_list)
 			printk(KERN_ERR "capidrv: bug in free_plci()\n");
+		card->nbchan--;
 	}
 	kfree(card->bchans);
-	del_timer(&card->listentimer);
+	card->bchans = 0;
+
+	if (debugmode)
+		printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
+					card->contrnr, card->myid);
 
 	cmd.command = ISDN_STAT_UNLOAD;
 	cmd.driver = card->myid;
 	card->interface.statcallb(&cmd);
 
+	if (debugmode)
+		printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
+					card->contrnr, card->myid);
+
+	spin_lock_irqsave(&global_lock, flags);
+	for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
+		if (*pp == card) {
+			*pp = (*pp)->next;
+			card->next = 0;
+			global.ncontr--;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&global_lock, flags);
+
 	kfree(card);
 
 	printk(KERN_INFO "%s: now down.\n", card->name);
@@ -2539,12 +2557,10 @@
 #ifdef MODULE
 void cleanup_module(void)
 {
-	capidrv_contr *card, *next;
-	long flags;
 	char rev[10];
 	char *p;
 
-	if ((p = strchr(revision, ':'))) {
+	if ((p = strchr(revision, ':')) != 0) {
 		strcpy(rev, p + 1);
 		p = strchr(rev, '$');
 		*p = 0;
@@ -2552,21 +2568,10 @@
 		strcpy(rev, " ??? ");
 	}
 
-	for (card = global.contr_list; card; card = next) {
-		next = card->next;
-		disable_dchannel_trace(card);
-	}
-
-    	save_flags(flags);
-    	cli();
-	for (card = global.contr_list; card; card = next) {
-		next = card->next;
-		capidrv_delcontr(card->contrnr);
-	}
-	restore_flags(flags);
-
 	(void) (*capifuncs->capi_release) (global.appid);
+
 	detach_capi_interface(&cuser);
+
 	proc_exit();
 
 	printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/capifs.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/avmb1/capifs.c	Thu Apr 13 17:06:00 2000
@@ -1,11 +1,15 @@
 /*
- * $Id: capifs.c,v 1.5 2000/03/13 17:49:52 calle Exp $
+ * $Id: capifs.c,v 1.6 2000/04/03 13:29:25 calle Exp $
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
  *
  * Heavily based on devpts filesystem from H. Peter Anvin
  * 
  * $Log: capifs.c,v $
+ * Revision 1.6  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.5  2000/03/13 17:49:52  calle
  * make it running with 2.3.51.
  *
@@ -56,7 +60,7 @@
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
 
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.6 $";
 
 struct capifs_ncci {
 	struct inode *inode;
@@ -554,6 +558,8 @@
 	char *p;
 	int err;
 
+	MOD_INC_USE_COUNT;
+
 	if ((p = strchr(revision, ':'))) {
 		strcpy(rev, p + 1);
 		p = strchr(rev, '$');
@@ -562,13 +568,16 @@
 		strcpy(rev, "1.0");
 
 	err = register_filesystem(&capifs_fs_type);
-	if (err)
+	if (err) {
+		MOD_DEC_USE_COUNT;
 		return err;
+	}
 #ifdef MODULE
         printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev);
 #else
 	printk(KERN_NOTICE "capifs: Rev%s: started\n", rev);
 #endif
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/kcapi.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/avmb1/kcapi.c	Fri Apr 21 15:17:57 2000
@@ -1,11 +1,22 @@
 /*
- * $Id: kcapi.c,v 1.13 2000/03/03 15:50:42 calle Exp $
+ * $Id: kcapi.c,v 1.15 2000/04/06 15:01:25 calle Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: kcapi.c,v $
+ * Revision 1.15  2000/04/06 15:01:25  calle
+ * Bugfix: crash in capidrv.c when reseting a capi controller.
+ * - changed code order on remove of controller.
+ * - using tq_schedule for notifier in kcapi.c.
+ * - now using spin_lock_irqsave() and spin_unlock_irqrestore().
+ * strange: sometimes even MP hang on unload of isdn.o ...
+ *
+ * Revision 1.14  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.13  2000/03/03 15:50:42  calle
  * - kernel CAPI:
  *   - Changed parameter "param" in capi_signal from __u32 to void *.
@@ -98,7 +109,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.13 $";
+static char *revision = "$Revision: 1.15 $";
 
 /* ------------------------------------------------------------- */
 
@@ -270,7 +281,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -541,20 +552,21 @@
 	struct capi_notifier *tail;
 } notifier_list;
 
+static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;
+
 static inline void notify_enqueue(struct capi_notifier *np)
 {
 	struct capi_notifier_list *q = &notifier_list;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&notifier_lock, flags);
 	if (q->tail) {
 		q->tail->next = np;
 		q->tail = np;
 	} else {
 		q->head = q->tail = np;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&notifier_lock, flags);
 }
 
 static inline struct capi_notifier *notify_dequeue(void)
@@ -563,15 +575,14 @@
 	struct capi_notifier *np = 0;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&notifier_lock, flags);
 	if (q->head) {
 		np = q->head;
 		if ((q->head = np->next) == 0)
  			q->tail = 0;
 		np->next = 0;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&notifier_lock, flags);
 	return np;
 }
 
@@ -580,18 +591,24 @@
 {
 	struct capi_notifier *np;
 
+	MOD_INC_USE_COUNT;
 	np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
-	if (!np)
+	if (!np) {
+		MOD_DEC_USE_COUNT;
 		return -1;
+	}
 	memset(np, 0, sizeof(struct capi_notifier));
 	np->cmd = cmd;
 	np->controller = controller;
 	np->applid = applid;
 	np->ncci = ncci;
 	notify_enqueue(np);
-	MOD_INC_USE_COUNT;
-	queue_task(&tq_state_notify, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+	/*
+	 * The notifier will result in adding/deleteing
+	 * of devices. Devices can only removed in
+	 * user process, not in bh.
+	 */
+	queue_task(&tq_state_notify, &tq_scheduler);
 	return 0;
 }
 
@@ -1732,6 +1749,8 @@
 	char *p;
 	char rev[10];
 
+	MOD_INC_USE_COUNT;
+
 	skb_queue_head_init(&recv_queue);
 	/* init_bh(CAPI_BH, do_capi_bh); */
 
@@ -1773,6 +1792,7 @@
 	(void)c4_init();
 #endif
 #endif
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/t1isa.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/avmb1/t1isa.c	Thu Apr 13 09:03:03 2000
@@ -1,11 +1,15 @@
 /*
- * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 calle Exp $
+ * $Id: t1isa.c,v 1.11 2000/04/03 13:29:25 calle Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1isa.c,v $
+ * Revision 1.11  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.10  2000/02/02 18:36:04  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -81,7 +85,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.11 $";
 
 /* ------------------------------------------------------------- */
 
@@ -598,6 +602,9 @@
 {
 	struct capi_driver *driver = &t1isa_driver;
 	char *p;
+	int retval = 0;
+
+	MOD_INC_USE_COUNT;
 
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
@@ -612,9 +619,11 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
-		return -EIO;
+		retval = -EIO;
 	}
-	return 0;
+
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.3.99-pre5/linux/drivers/isdn/avmb1/t1pci.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/avmb1/t1pci.c	Thu Apr 13 09:03:03 2000
@@ -1,11 +1,18 @@
 /*
- * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $
+ * $Id: t1pci.c,v 1.7 2000/04/07 15:26:55 calle Exp $
  * 
  * Module for AVM T1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1pci.c,v $
+ * Revision 1.7  2000/04/07 15:26:55  calle
+ * better error message if cabel not connected or T1 has no power.
+ *
+ * Revision 1.6  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.5  2000/02/02 18:36:04  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -47,7 +54,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.7 $";
 
 #undef CONFIG_T1PCI_DEBUG
 #undef CONFIG_T1PCI_POLLDEBUG
@@ -164,7 +171,11 @@
 	b1dma_reset(card);
 
 	if ((retval = t1pci_detect(card)) != 0) {
-		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+		if (retval < 6)
+			printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+					driver->name, card->port, retval);
+		else
+			printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
 					driver->name, card->port, retval);
                 iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
 	        kfree(card->ctrlinfo);
@@ -264,6 +275,8 @@
 	char *p;
 	int retval;
 
+	MOD_INC_USE_COUNT;
+
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
 		p = strchr(driver->revision, '$');
@@ -277,6 +290,7 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -284,6 +298,7 @@
 	if (!pci_present()) {
 		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
     		detach_capi_driver(driver);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -305,6 +320,7 @@
 #ifdef MODULE
 			cleanup_module();
 #endif
+			MOD_DEC_USE_COUNT;
 			return retval;
 		}
 		ncards++;
@@ -312,12 +328,15 @@
 	if (ncards) {
 		printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n",
 				driver->name, ncards);
+		MOD_DEC_USE_COUNT;
 		return 0;
 	}
 	printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -ESRCH;
 #else
 	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -EIO;
 #endif
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- v2.3.99-pre5/linux/drivers/isdn/hisax/hisax.h	Sat Feb 26 22:31:46 2000
+++ linux/drivers/isdn/hisax/hisax.h	Thu Apr 13 09:03:03 2000
@@ -1,8 +1,11 @@
-/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $
+/* $Id: hisax.h,v 2.42 2000/04/09 19:02:44 keil Exp $
 
  *   Basic declarations, defines and prototypes
  *
  * $Log: hisax.h,v $
+ * Revision 2.42  2000/04/09 19:02:44  keil
+ * retry pump modulation settings if it fails
+ *
  * Revision 2.41  2000/02/26 00:35:13  keil
  * Fix skb freeing in interrupt context
  *
@@ -500,6 +503,7 @@
 	u_char mod;
 	u_char newcmd;
 	u_char newmod;
+	char try_mod;
 	struct timer_list ftimer;
 	u_char *rcvbuf;         /* B-Channel receive Buffer */
 	u_char conmsg[16];
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c
--- v2.3.99-pre5/linux/drivers/isdn/hisax/isar.c	Sat Feb 26 22:31:46 2000
+++ linux/drivers/isdn/hisax/isar.c	Thu Apr 13 09:03:03 2000
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.10 2000/02/26 00:35:13 keil Exp $
+/* $Id: isar.c,v 1.11 2000/04/09 19:02:44 keil Exp $
 
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: isar.c,v $
+ * Revision 1.11  2000/04/09 19:02:44  keil
+ * retry pump modulation settings if it fails
+ *
  * Revision 1.10  2000/02/26 00:35:13  keil
  * Fix skb freeing in interrupt context
  *
@@ -1085,13 +1088,14 @@
 						break;
 					case PCTRL_CMD_FRH:
 					case PCTRL_CMD_FRM:
-						p1 = bcs->hw.isar.newmod;
+						p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
 						bcs->hw.isar.newmod = 0;
 						bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
 						bcs->hw.isar.newcmd = 0;
 						sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
 							bcs->hw.isar.cmd, 1, &p1);
 						bcs->hw.isar.state = STFAX_LINE;
+						bcs->hw.isar.try_mod = 3;
 						break;
 					default:
 						if (cs->debug & L1_DEB_HSCX)
@@ -1117,13 +1121,14 @@
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "pump stev RSP_SILDET");
 			if (bcs->hw.isar.state == STFAX_SILDET) {
-				p1 = bcs->hw.isar.newmod;
+				p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
 				bcs->hw.isar.newcmd = 0;
 				sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
 					bcs->hw.isar.cmd, 1, &p1);
 				bcs->hw.isar.state = STFAX_LINE;
+				bcs->hw.isar.try_mod = 3;
 			}
 			break;
 		case PSEV_RSP_SILOFF:
@@ -1131,6 +1136,17 @@
 				debugl1(cs, "pump stev RSP_SILOFF");
 			break;
 		case PSEV_RSP_FCERR:
+			if (bcs->hw.isar.state == STFAX_LINE) {
+				if (cs->debug & L1_DEB_HSCX)
+					debugl1(cs, "pump stev RSP_FCERR try %d",
+						bcs->hw.isar.try_mod);
+				if (bcs->hw.isar.try_mod--) {
+					sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+						bcs->hw.isar.cmd, 1,
+						&bcs->hw.isar.mod);
+					break;
+				}
+			}
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "pump stev RSP_FCERR");
 			bcs->hw.isar.state = STFAX_ESCAPE;
@@ -1441,6 +1457,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FTM) &&
 				(bcs->hw.isar.mod == para)) {
@@ -1463,6 +1480,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FTH) &&
 				(bcs->hw.isar.mod == para)) {
@@ -1485,6 +1503,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FRM) &&
 				(bcs->hw.isar.mod == para)) {
@@ -1507,6 +1526,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FRH) &&
 				(bcs->hw.isar.mod == para)) {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl2.c	Thu Nov 11 20:11:38 1999
+++ linux/drivers/isdn/hisax/isdnl2.c	Thu Apr 13 09:03:03 2000
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 2.20 1999/08/25 16:52:04 keil Exp $
+/* $Id: isdnl2.c,v 2.22 2000/04/12 20:28:37 keil Exp $
 
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -11,6 +11,13 @@
  *              Fritz Elfert
  *
  * $Log: isdnl2.c,v $
+ * Revision 2.22  2000/04/12 20:28:37  keil
+ * a I frame may be contain zero information bytes
+ *
+ * Revision 2.21  2000/04/12 16:41:01  kai
+ * fix max iframe size
+ * fix bug in multicasting DL_RELEASE_IND
+ *
  * Revision 2.20  1999/08/25 16:52:04  keil
  * Make gcc on AXP happy
  *
@@ -83,7 +90,7 @@
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.20 $";
+const char *l2_revision = "$Revision: 2.22 $";
 
 static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
@@ -361,7 +368,7 @@
 int
 iframe_error(struct PStack *st, struct sk_buff *skb)
 {
-	int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 1 : 0);
+	int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
 	int rsp = *skb->data & 0x2;
 
 	if (test_bit(FLG_ORIG, &st->l2.flag))
@@ -371,7 +378,7 @@
 		return 'L';
 
 
-	if (skb->len <= i)
+	if (skb->len < i)
 		return 'N';
 
 	if ((skb->len - i) > st->l2.maxlen)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl3.c	Thu Nov 11 20:11:38 1999
+++ linux/drivers/isdn/hisax/isdnl3.c	Thu Apr 13 09:03:03 2000
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 2.10 1999/07/21 14:46:19 keil Exp $
+/* $Id: isdnl3.c,v 2.11 2000/04/12 16:41:01 kai Exp $
 
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -11,6 +11,10 @@
  *              Fritz Elfert
  *
  * $Log: isdnl3.c,v $
+ * Revision 2.11  2000/04/12 16:41:01  kai
+ * fix max iframe size
+ * fix bug in multicasting DL_RELEASE_IND
+ *
  * Revision 2.10  1999/07/21 14:46:19  keil
  * changes from EICON certification
  *
@@ -68,7 +72,7 @@
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.10 $";
+const char *l3_revision = "$Revision: 2.11 $";
 
 static
 struct Fsm l3fsm =
@@ -375,10 +379,13 @@
 l3ml3p(struct PStack *st, int pr)
 {
 	struct l3_process *p = st->l3.proc;
+	struct l3_process *np;
 
 	while (p) {
+		/* p might be kfreed under us, so we need to save where we want to go on */
+		np = p->next;
 		st->l3.l3ml3(st, pr, p);
-		p = p->next;
+		p = np;
 	}
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc
--- v2.3.99-pre5/linux/drivers/isdn/hisax/md5sums.asc	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/hisax/md5sums.asc	Thu Apr 13 09:03:03 2000
@@ -8,8 +8,8 @@
 # 
 3fb9c99465857a4c136ae2881f4e30ba  isac.c
 dd3955847bbf680b41233478fe521d88  isdnl1.c
-bb51bd223040b511c18f091da5ab6456  isdnl2.c
-b7aa7f97b2374967a4aca7c52991142c  isdnl3.c
+d362523462c424a8bce8b596ed5bdf2e  isdnl2.c
+92ea268891c222963a6ca70935bf1556  isdnl3.c
 a23fbf8879c1432b04640b8b04bdf419  tei.c
 838791b14269ec94c74ba4ae89c022e6  callc.c
 bf9605b36429898f7be6630034e83230  cert.c
@@ -23,9 +23,9 @@
 Version: 2.6.3i
 Charset: noconv
 
-iQCVAwUBONlcejpxHvX/mS9tAQFWYAP/WmxgwQ7W6gVnsMkUlwzE1TKGWVJdGUTC
-7WrKEtdweuzW3/7WEzjBoZgUEcpugJYK3JENby1xjh3yIHfws4HqLme1yXAmkYUK
-6LmW96HC2g4wj7PH0hvLnzTOtXDGTppU7KJibbB+ziyhBbs6SGXOD4zHrCWmT9ld
-CURhfNgftIs=
-=AA+Q
+iQCVAwUBOPT2aTpxHvX/mS9tAQFJyAQAj+eY8MhPxQ2TS3rtfjK7bv8jrOGeJYu6
+P0YPnkkc09pCA6UdmYP6VSFkhtDS43HEZiGMb1MV/Y4LQ4wVDNrFDk9AyUNhP2/0
+gY+nYON6hT9ilXYqsbqoqGmh5qLaxj64p9mKu+MIgZ69CS4g7aj/OAXWB06zh7li
+MiC65PNo6k0=
+=d7xA
 -----END PGP SIGNATURE-----
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- v2.3.99-pre5/linux/drivers/isdn/hisax/niccy.c	Thu Nov 11 20:11:38 1999
+++ linux/drivers/isdn/hisax/niccy.c	Thu Apr 13 09:03:03 2000
@@ -1,4 +1,4 @@
-/* $Id: niccy.c,v 1.8 1999/08/11 21:01:33 keil Exp $
+/* $Id: niccy.c,v 1.10 2000/04/11 11:12:39 keil Exp $
 
  * niccy.c  low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
  *          compatible (SAGEM cybermodem)
@@ -8,6 +8,12 @@
  * Thanks to Dr. Neuhaus and SAGEM for informations
  *
  * $Log: niccy.c,v $
+ * Revision 1.10  2000/04/11 11:12:39  keil
+ * cleanup
+ *
+ * Revision 1.9  2000/04/09 19:09:19  keil
+ * Bugfix: reset IRQ enable only valid for PCI version
+ *
  * Revision 1.8  1999/08/11 21:01:33  keil
  * new PCI codefix
  *
@@ -42,7 +48,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.8 $";
+const char *niccy_revision = "$Revision: 1.10 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -228,12 +234,13 @@
 static void
 niccy_reset(struct IsdnCardState *cs)
 {
-	int val, nval;
-	
-	val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
-	nval = val | PCI_IRQ_ENABLE;
-	outl(nval, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+	if (cs->subtyp == NICCY_PCI) {
+		int val;
 
+		val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+		val |= PCI_IRQ_ENABLE;
+		outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+	}
 	inithscxisac(cs, 3);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.3.99-pre5/linux/drivers/isdn/isdn_common.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/isdn_common.c	Thu Apr 13 09:03:03 2000
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.100 2000/03/03 16:37:11 kai Exp $
+/* $Id: isdn_common.c,v 1.101 2000/04/07 14:50:34 calle Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -21,6 +21,11 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.101  2000/04/07 14:50:34  calle
+ * Bugfix: on my system 2.3.99-pre3 Dual PII 350, unload of module isdn.o
+ *         hangs if vfree is called with interrupt disabled. After moving
+ * 	restore_flags in front of vfree it doesn't hang.
+ *
  * Revision 1.100  2000/03/03 16:37:11  kai
  * incorporated some cosmetic changes from the official kernel tree back
  * into CVS
@@ -453,7 +458,7 @@
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.100 $";
+static char *isdn_revision = "$Revision: 1.101 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -2780,12 +2785,14 @@
 	}
 	if (devfs_unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
 		printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
+		restore_flags(flags);
 	} else {
 		isdn_cleanup_devfs();
 		del_timer(&dev->timer);
+		restore_flags(flags);
+		/* call vfree with interrupts enabled, else it will hang */
 		vfree(dev);
 		printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
 	}
-	restore_flags(flags);
 }
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.3.99-pre5/linux/drivers/isdn/isdn_net.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/isdn/isdn_net.c	Thu Apr 13 09:03:03 2000
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.122 2000/03/20 22:37:46 detabc Exp $
+/* $Id: isdn_net.c,v 1.125 2000/04/05 21:25:55 detabc Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -21,6 +21,15 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.125  2000/04/05 21:25:55  detabc
+ * add leased-line support to abc-stuff
+ *
+ * Revision 1.124  2000/04/03 21:07:22  detabc
+ * change write_super handling for abc-stuff
+ *
+ * Revision 1.123  2000/04/03 19:14:36  kai
+ * fix "isdn BUG at isdn_net.c:1440!"
+ *
  * Revision 1.122  2000/03/20 22:37:46  detabc
  * modify abc-extension to work together with the new LL.
  * remove abc frame-counter (is obsolete now).
@@ -647,7 +656,7 @@
 int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
 
-char *isdn_net_revision = "$Revision: 1.122 $";
+char *isdn_net_revision = "$Revision: 1.125 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -1437,12 +1446,16 @@
 void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
 {
 	if (in_interrupt()) {
-		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		// we can't grab the lock from irq context, 
+		// so we just queue the packet
+		skb_queue_tail(&lp->super_tx_queue, skb); 
+		queue_task(&lp->tqueue, &tq_immediate);
 		return;
 	}
 
 	spin_lock_bh(&lp->xmit_lock);
-	if (!isdn_net_lp_busy(lp)) {
+	if (!isdn_net_lp_busy(lp))
+	{
 		isdn_net_writebuf_skb(lp, skb);
 	} else {
 		skb_queue_tail(&lp->super_tx_queue, skb);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.3.99-pre5/linux/drivers/net/3c509.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/net/3c509.c	Tue Apr 25 16:53:13 2000
@@ -168,7 +168,7 @@
 };
 #endif
 
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
 struct el3_isapnp_adapters_struct {
 	unsigned short vendor, function;
 	char *name;
@@ -187,7 +187,7 @@
 	{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
 };
 #endif /* CONFIG_ISAPNP */
-#if defined(CONFIG_ISAPNP) || defined(MODULE)
+#if defined(__ISAPNP__) || defined(MODULE)
 static int nopnp = 0;
 #endif
 
@@ -198,7 +198,7 @@
 	u16 phys_addr[3];
 	static int current_tag = 0;
 	int mca_slot = -1;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
 	static int pnp_cards = 0;
 #endif
 
@@ -294,7 +294,7 @@
 	}
 #endif
 
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
 	if (nopnp == 1)
 		goto no_pnp;
 
@@ -376,7 +376,7 @@
 		phys_addr[i] = htons(id_read_eeprom(i));
 	}
 
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
 	if (nopnp == 0) {
 		/* The ISA PnP 3c509 cards respond to the ID sequence.
 		   This check is needed in order not to register them twice. */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.3.99-pre5/linux/drivers/net/3c515.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/net/3c515.c	Tue Apr 25 16:53:13 2000
@@ -46,7 +46,6 @@
 #define RX_RING_SIZE	16
 #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/isapnp.h>
@@ -353,7 +352,7 @@
 	{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
 };
 
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
 struct corkscrew_isapnp_adapters_struct {
 	unsigned short vendor, function;
 	char *name;
@@ -445,7 +444,7 @@
 	static int ioaddr;
 	static int pnp_cards = 0;
 
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
 	if(nopnp == 1)
 		goto no_pnp;
 	for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
@@ -503,12 +502,12 @@
 		}
 	}
 no_pnp:
-#endif /* not CONFIG_ISAPNP */
+#endif /* not __ISAPNP__ */
 
 	/* Check all locations on the ISA bus -- evil! */
 	for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
 		int irq;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
 		/* Make sure this was not already picked up by isapnp */
 		if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue;
 		if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.3.99-pre5/linux/drivers/net/3c59x.c	Mon Mar 27 08:08:25 2000
+++ linux/drivers/net/3c59x.c	Mon Apr 24 15:17:06 2000
@@ -1,6 +1,6 @@
-/* 3c59x.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
+/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
 /*
-	Written 1996-1998 by Donald Becker.
+	Written 1996-1999 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -13,14 +13,51 @@
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
- Version history:
- 	0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
- 	0.99H+lk1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
-		Remove compatibility defines for kernel versions < 2.2.x.
-		Update for new 2.3.x module interface
-		
+	Linux Kernel Additions:
+	
+	LK1.1.2 (March 19, 2000)
+	* New PCI interface (jgarzik)
+
+*/
+
+/*
+    22Apr00, Andrew Morton <andrewm@uow.edu.au>
+    - Merged with 3c575_cb.c
+    - Don't set RxComplete in boomerang interrupt enable reg
+    - spinlock in vortex_timer to protect mdio functions
+    - disable local interrupts around call to vortex_interrupt in
+      vortex_tx_timeout() (So vortex_interrupt can use spin_lock())
+    - Select window 3 in vortex_timer()'s write to Wn3_MAC_Ctrl
+    - In vortex_start_xmit(), move the lock to _after_ we've altered
+      vp->cur_tx and vp->tx_full.  This defeats the race between
+      vortex_start_xmit() and vortex_interrupt which was identified
+      by Bogdan Costescu.
+    - Merged back support for six new cards from various sources
+    - Set vortex_have_pci if pci_module_init returns zero (fixes cardbus
+      insertion oops)
+    - Tell it that 3c905C has NWAY for 100bT autoneg
+    - Fix handling of SetStatusEnd in 'Too much work..' code, as
+      per 2.3.99's 3c575_cb (Dave Hinds).
+    - Split ISR into two for vortex & boomerang
+    - Fix MOD_INC/DEC races
+    - Handle resource allocation failures.
+    - Fix 3CCFE575CT LED polarity
+    - Make tx_interrupt_mitigation the default
+    - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs.
+    - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
+*/
+
+/*
+ * FIXME: This driver _could_ support MTU changing, but doesn't.  See Don's hamaci.c implementation
+ * as well as other drivers
+ *
+ * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k
+ * due to dead code elimination.  There will be some performance benefits from this due to
+ * elimination of all the tests and reduced cache footprint.
  */
 
+static char *version =
+"3c59x.c:v0.99L+LK1.1.2+AKPM  24 Apr 2000  Donald Becker and others  http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -29,7 +66,13 @@
 /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
 static const int mtu = 1500;
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 32;
+
+/* Allow aggregation of Tx interrupts.  Saves CPU load at the cost
+ * of possible Tx stalls if the system is blocking interrupts
+ * somewhere else.  Undefine this to disable.
+ */
+#define tx_interrupt_mitigation 1
 
 /* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
 #define vortex_debug debug
@@ -52,8 +95,12 @@
 #define RX_RING_SIZE	32
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
-#include <linux/config.h>
-#include <linux/version.h>
+#ifndef __OPTIMIZE__
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -61,11 +108,11 @@
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/in.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -80,14 +127,8 @@
 
 #include <linux/delay.h>
 
-#define PCI_SUPPORT_VER2
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-
-static char *version __initdata =
-"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
-
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
+MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
@@ -111,6 +152,10 @@
    code size of a per-interface flag is not worthwhile. */
 static char mii_preamble_required = 0;
 
+#define PFX "3c59x: "
+
+
+
 /*
 				Theory of Operation
 
@@ -168,7 +213,6 @@
 passing the full-sized skbuff to the queue layer for all frames vs. the
 copying cost of copying a frame to a correctly-sized skbuff.
 
-
 IIIC. Synchronization
 The driver runs as two independent, single-threaded flows of control.  One
 is the send-packet routine, which enforces single-threaded use by the
@@ -195,68 +239,163 @@
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
-struct pci_id_info {
+
+enum {	IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
+	EEPROM_230=8,	/* AKPM: Uses 0x230 as the base bitmpas for EEPROM reads */
+	HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
+
+
+enum vortex_chips {
+	CH_3C590 = 0,
+	CH_3C592,
+	CH_3C597,
+	CH_3C595_1,
+	CH_3C595_2,
+
+	CH_3C595_3,
+	CH_VORTEX,
+	CH_3C900_1,
+	CH_3C900_2,
+	CH_3C900_3,
+
+	CH_3C900_4,
+	CH_3C900_5,
+	CH_3C900B_FL,
+	CH_3C905_1,
+	CH_3C905_2,
+
+	CH_3C905B_1,
+	CH_3C905B_2,
+	CH_3C905B_FX,
+	CH_3C905C,
+	CH_3C980,
+
+	CH_3CSOHO100_TX,
+	CH_3C555,
+	CH_3C575_1,
+	CH_3CCFE575,
+	CH_3CCFE575CT,
+
+	CH_3CCFE656,
+	CH_3CCFEM656,
+	CH_3C450,
+};
+
+
+/* note: this array directly indexed by above enums, and MUST
+ * be kept in sync with both the enums above, and the PCI device
+ * table below
+ */
+static struct vortex_chip_info {
 	const char *name;
-	u16	vendor_id, device_id, device_id_mask, flags;
-	int drv_flags, io_size;
-	struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-
-enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
-	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-static struct net_device *vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, int dev_id, int card_idx);
-
-static struct pci_id_info pci_tbl[] = {
-	{"3c590 Vortex 10Mbps",			0x10B7, 0x5900, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3c595 Vortex 100baseTx",		0x10B7, 0x5950, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3c595 Vortex 100baseT4",		0x10B7, 0x5951, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3c595 Vortex 100base-MII",	0x10B7, 0x5952, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3Com Vortex",					0x10B7, 0x5900, 0xff00,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-	{"3c900 Boomerang 10baseT",		0x10B7, 0x9000, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-	{"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-	{"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c900B-FL Cyclone 10base-FL",	0x10B7, 0x900A, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c905 Boomerang 100baseTx",	0x10B7, 0x9050, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3c905 Boomerang 100baseT4",	0x10B7, 0x9051, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3c905B Cyclone 100baseTx",	0x10B7, 0x9055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
-	{"3c905B Cyclone 10/100/BNC",	0x10B7, 0x9058, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
-	{"3c905B-FX Cyclone 100baseFx",	0x10B7, 0x905A, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c905C Tornado",	0x10B7, 0x9200, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c980 Cyclone",	0x10B7, 0x9800, 0xfff0,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3cSOHO100-TX Hurricane",	0x10B7, 0x7646, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c555 Laptop Hurricane",	0x10B7, 0x5055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c575 Boomerang CardBus",		0x10B7, 0x5057, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3CCFE575 Cyclone CardBus",	0x10B7, 0x5157, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
-	 128, vortex_probe1},
-	{"3CCFE656 Cyclone CardBus",	0x10B7, 0x6560, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
-	 128, vortex_probe1},
-	{"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3Com Boomerang (unknown version)",	0x10B7, 0x9000, 0xff00,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+	int flags;
+	int drv_flags;
+	int io_size;
+} vortex_info_tbl[] = {
+	{"3c590 Vortex 10Mbps",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c592 EISA 10mbps Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c597 EISA Fast Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c595 Vortex 100baseTx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c595 Vortex 100baseT4",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+
+	{"3c595 Vortex 100base-MII",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+#define EISA_TBL_OFFSET	6		/* Offset of this entry for vortex_eisa_init */
+	{"3Com Vortex",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+	{"3c900 Boomerang 10baseT",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+	{"3c900 Boomerang 10Mbps Combo",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+	{"3c900 Cyclone 10Mbps TPO",						/* AKPM: from Don's 0.99M */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+
+	{"3c900 Cyclone 10Mbps Combo",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c900 Cyclone 10Mbps TPC",						/* AKPM: from Don's 0.99M */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c900B-FL Cyclone 10base-FL",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c905 Boomerang 100baseTx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+	{"3c905 Boomerang 100baseT4",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+
+	{"3c905B Cyclone 100baseTx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{"3c905B Cyclone 10/100/BNC",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{"3c905B-FX Cyclone 100baseFx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c905C Tornado",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{"3c980 Cyclone",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+
+	{"3cSOHO100-TX Hurricane",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c555 Laptop Hurricane",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c575 Boomerang CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 64, },
+	{"3CCFE575 Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+	{"3CCFE575CT Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+
+	{"3CCFE656 Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+	{"3CCFEM656 Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+	{"3c450 Cyclone/unknown",						/* AKPM: from Don's 0.99N */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{0,}, /* 0 terminated list. */
+};
+
+
+static struct pci_device_id vortex_pci_tbl[] __devinitdata = {
+	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
+	{ 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 },
+	{ 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 },
+	{ 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 },
+	{ 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 },
+
+	{ 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 },
+	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX },
+	{ 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 },
+	{ 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 },
+	{ 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
+
+	{ 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 },
+	{ 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 },
+	{ 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL },
+	{ 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 },
+	{ 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 },
+
+	{ 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 },
+	{ 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
+	{ 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
+	{ 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
+	{ 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
+
+	{ 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
+	{ 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
+	{ 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
+	{ 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
+	{ 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
+
+	{ 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
+	{ 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
+	{ 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
 	{0,},						/* 0 terminated list. */
 };
+MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
+
 
 /* Operational definitions.
    These are not used by other compilation units and thus are not
@@ -392,7 +531,7 @@
 };
 
 /* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20 };
+enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
 
 struct vortex_private {
 	/* The Rx and Tx rings should be quad-word-aligned. */
@@ -403,36 +542,38 @@
 	/* The addresses of transmit- and receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	struct net_device *next_module;
+	struct net_device *next_module;		/* NULL if PCI device */
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	struct net_device_stats stats;
-	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
-	dma_addr_t tx_skb_dma;	/* Allocated DMA address for bus master ctrl DMA.   */
+	struct sk_buff *tx_skb;				/* Packet being eaten by bus master ctrl.  */
+	dma_addr_t tx_skb_dma;				/* Allocated DMA address for bus master ctrl DMA.   */
 
 	/* PCI configuration space information. */
-	u8 pci_bus, pci_devfn;		/* PCI bus location, for power management. */
+	struct pci_dev *pdev;
 	char *cb_fn_base;			/* CardBus function status addr space. */
 	int chip_id;
-	struct pci_dev *pdev;			/* Device for DMA mapping */
 
 	/* The remainder are related to chip state, mostly media selection. */
-	unsigned long in_interrupt;
-	struct timer_list timer;	/* Media selection timer. */
-	int options;				/* User-settable misc. driver options. */
-	unsigned int media_override:3, 			/* Passed-in media type. */
+	struct timer_list timer;			/* Media selection timer. */
+	int options;						/* User-settable misc. driver options. */
+	unsigned int media_override:4, 		/* Passed-in media type. */
 		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
 		full_duplex:1, force_fd:1, autoselect:1,
-		bus_master:1,				/* Vortex can only do a fragment bus-m. */
+		bus_master:1,					/* Vortex can only do a fragment bus-m. */
 		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
-		hw_csums:1,				/* Has hardware checksums. */
-		tx_full:1;
+		hw_csums:1,						/* Has hardware checksums. */
+		tx_full:1,
+		open:1;
 	u16 status_enable;
 	u16 intr_enable;
 	u16 available_media;				/* From Wn3_Options. */
 	u16 capabilities, info1, info2;		/* Various, from EEPROM. */
 	u16 advertising;					/* NWay media advertisement */
 	unsigned char phys[2];				/* MII device addresses. */
+	u16 deferred;						/* Resend these interrupts when we
+										 * bale from the ISR */
+	spinlock_t lock;
 };
 
 /* The action to take with a media selection timer tick.
@@ -446,9 +587,9 @@
 static struct media_table {
 	char *name;
 	unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
-		mask:8,				/* The transceiver-present bit in Wn3_Config.*/
-		next:8;				/* The media type to try next. */
-	int wait;			/* Time before we check media status. */
+		mask:8,						/* The transceiver-present bit in Wn3_Config.*/
+		next:8;						/* The media type to try next. */
+	int wait;						/* Time before we check media status. */
 } media_tbl[] = {
   {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
   { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
@@ -463,329 +604,245 @@
   { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
 };
 
-#ifndef CARDBUS
-static int vortex_scan(struct pci_id_info pci_tbl[]);
-#endif
+static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq,
+				   int chip_idx, int card_idx);
+static void vortex_up(struct net_device *dev);
+static void vortex_down(struct net_device *dev);
 static int vortex_open(struct net_device *dev);
 static void mdio_sync(long ioaddr, int bits);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static void mdio_write(long ioaddr, int phy_id, int location, int value);
 static void vortex_timer(unsigned long arg);
 static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void vortex_tx_timeout(struct net_device *dev);
 static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int vortex_rx(struct net_device *dev);
 static int boomerang_rx(struct net_device *dev);
 static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int vortex_close(struct net_device *dev);
 static void update_stats(long ioaddr, struct net_device *dev);
 static struct net_device_stats *vortex_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void vortex_tx_timeout(struct net_device *dev);
+static void acpi_set_WOL(struct net_device *dev);
 
-
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Option count limit only -- unlimited interfaces are supported. */
 #define MAX_UNITS 8
 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct net_device *root_vortex_dev = NULL;
 
-#ifndef CARDBUS
+
+/* A list of all installed Vortex EISA devices, for removing the driver module. */
+static struct net_device *root_vortex_eisa_dev = NULL;
+
 /* Variables to work-around the Compaq PCI BIOS32 problem. */
 static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-#endif
 
-#ifdef CARDBUS
+static int vortex_cards_found = 0;
 
-#include <pcmcia/driver_ops.h>
-
-static dev_node_t *vortex_attach(dev_locator_t *loc)
+static void vortex_suspend (struct pci_dev *pdev)
 {
-	u16 dev_id, vendor_id;
-	u32 io;
-	u8 irq;
-	struct net_device *dev;
-	struct pci_dev *pdev;
-	int chip_idx;
+	struct net_device *dev = pdev->driver_data;
 
-	if (loc->bus != LOC_PCI) return NULL;
-	pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
-	if (!pdev) return NULL;
-	io = pdev->resource[0].start;
-	irq = pdev->irq;
-	vendor_id = pdev->vendor;
-	dev_id = pdev->device;
-	printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
-		   pdev->bus->number, pdev->devfn, dev_id);
-	io &= ~3;
-	if (io == 0 || irq == 0) {
-		printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
-			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",
-			   io == 0 ? "I/O address" : "IRQ");
-		return NULL;
-	}
-	for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-		if (vendor_id == pci_tbl[chip_idx].vendor_id
-			&& (dev_id & pci_tbl[chip_idx].device_id_mask) ==
-			pci_tbl[chip_idx].device_id)
-			break;
-	if (pci_tbl[chip_idx].vendor_id == 0) { 		/* Compiled out! */
-		printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
-			   "vortex_attach().\n", vendor_id, dev_id);
-		return NULL;
-	}
-	dev = vortex_probe1(pdev, io, irq, chip_idx, MAX_UNITS+1);
-	if (dev) {
-		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-		strcpy(node->dev_name, dev->name);
-		node->major = node->minor = 0;
-		node->next = NULL;
-		MOD_INC_USE_COUNT;
-		return node;
-	}
-	return NULL;
-}
+	printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
 
-static void vortex_detach(dev_node_t *node)
-{
-	struct net_device **devp, **next;
-	printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
-	for (devp = &root_vortex_dev; *devp; devp = next) {
-		next = &((struct vortex_private *)(*devp)->priv)->next_module;
-		if (strcmp((*devp)->name, node->dev_name) == 0) break;
-	}
-	if (*devp) {
-		struct net_device *dev = *devp;
-		struct vortex_private *vp = dev->priv;
-		if (dev->flags & IFF_UP)
-			vortex_close(dev);
-		dev->flags &= ~(IFF_UP|IFF_RUNNING);
-		unregister_netdev(dev);
-		if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
-		kfree(dev);
-		*devp = *next;
-		kfree(vp);
-		kfree(node);
-		MOD_DEC_USE_COUNT;
+	if (dev && dev->priv) {
+		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+		if (vp->open) {
+			netif_device_detach(dev);
+			vortex_down(dev);
+		}
 	}
 }
 
-struct driver_operations vortex_ops = {
-	"3c575_cb", vortex_attach, NULL, NULL, vortex_detach
-};
-
-#endif  /* Cardbus support */
+static void vortex_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = pdev->driver_data;
 
+	printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name);
 
-static int __init vortex_init_module (void)
-{
-	if (vortex_debug)
-		printk(KERN_INFO "%s", version);
-#ifdef CARDBUS
-	register_driver(&vortex_ops);
-	return 0;
-#else
-	return vortex_scan(pci_tbl);
-#endif
+	if (dev && dev->priv) {
+		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+		if (vp->open) {
+			vortex_up(dev);
+			netif_device_attach(dev);
+		}
+	}
 }
 
-#ifndef CARDBUS
-static int vortex_scan(struct pci_id_info pci_tbl[])
+/* returns count found (>= 0), or negative on error */
+static int __init vortex_eisa_init (void)
 {
-	int cards_found = 0;
-	struct net_device *dev;
-
-	/* Allow an EISA-only driver. */
-#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
-	/* Ideally we would detect all cards in slot order.  That would
-	   be best done a central PCI probe dispatch, which wouldn't work
-	   well with the current structure.  So instead we detect 3Com cards
-	   in slot order. */
-	if (pci_present()) {
-		static int pci_index = 0;
-		unsigned char pci_bus, pci_device_fn;
-
-		for (;pci_index < 0xff; pci_index++) {
-			u16 vendor, device, pci_command, new_command, pwr_cmd;
-			int chip_idx, irq;
-			long ioaddr;
-			struct pci_dev *pdev;
-
-			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-									&pci_bus, &pci_device_fn)
-				!= PCIBIOS_SUCCESSFUL)
-				break;
-			pdev = pci_find_slot (pci_bus, pci_device_fn);
-			if (!pdev) continue;
-			vendor = pdev->vendor;
-			device = pdev->device;
-			for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-				if (vendor == pci_tbl[chip_idx].vendor_id
-					&& (device & pci_tbl[chip_idx].device_id_mask) ==
-					pci_tbl[chip_idx].device_id)
-					break;
-			if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
-				continue;
-
-			{
-				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-				ioaddr = pdev->resource[0].start;
-				irq = pdev->irq;
-			}
-
-			/* Power-up the card. */
-			pci_read_config_word(pdev, 0xe0, &pwr_cmd);
-			
-			if (pwr_cmd & 0x3) {
-				/* Save the ioaddr and IRQ info! */
-				printk(KERN_INFO "  A 3Com network adapter is powered down!"
-					   "  Setting the power state %4.4x->%4.4x.\n",
-					   pwr_cmd, pwr_cmd & ~3);
-				pci_write_config_word(pdev, 0xe0, pwr_cmd & ~3);
-				printk(KERN_INFO "  Setting the IRQ to %d, IOADDR to %#lx.\n",
-					   irq, ioaddr);
-				pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
-				pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, ioaddr);
-			}
-
-			if (ioaddr == 0) {
-				printk(KERN_WARNING "  A 3Com network adapter has been found, "
-					   "however it has not been assigned an I/O address.\n"
-					   "  You may need to power-cycle the machine for this "
-					   "device to work!\n");
-				continue;
-			}
-
-			if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-				continue;
-
-			/* Activate the card. */
-			pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	long ioaddr;
+	int rc;
+	int orig_cards_found = vortex_cards_found;
 
-			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-			if (pci_command != new_command) {
-				printk(KERN_INFO "  The PCI BIOS has not enabled the device "
-					   "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",
-					   pci_bus, pci_device_fn, pci_command, new_command);
-				pci_write_config_word(pdev, PCI_COMMAND, new_command);
-			}
+	/* Now check all slots of the EISA bus. */
+	if (!EISA_bus)
+		return 0;
 
-			dev = vortex_probe1(pdev, ioaddr, irq,
-					    chip_idx, cards_found);
+	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+		int device_id;
 
-			if (dev) {
-				/* Get and check the latency values.  On the 3c590 series
-				   the latency timer must be set to the maximum value to avoid
-				   data corruption that occurs when the timer expires during
-				   a transfer -- a bug in the Vortex chip only. */
-				u8 pci_latency;
-				u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
-				
-				pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-				if (pci_latency < new_latency) {
-					printk(KERN_INFO "%s: Overriding PCI latency"
-						   " timer (CFLT) setting of %d, new value is %d.\n",
-						   dev->name, pci_latency, new_latency);
-					pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
-				}
-				dev = 0;
-				cards_found++;
-			}
-		}
-	}
-#endif /* NO_PCI */
+		if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
+			continue;
 
-	/* Now check all slots of the EISA bus. */
-	if (EISA_bus) {
-		static long ioaddr = 0x1000;
-		for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
-			int device_id;
-			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
-				continue;
-			/* Check the standard EISA ID register for an encoded '3Com'. */
-			if (inw(ioaddr + 0xC80) != 0x6d50)
-				continue;
-			/* Check for a product that we support, 3c59{2,7} any rev. */
-			device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
-			if ((device_id & 0xFF00) != 0x5900)
-				continue;
-			vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
-				      4, cards_found);
-			cards_found++;
-		}
+		/* Check the standard EISA ID register for an encoded '3Com'. */
+		if (inw(ioaddr + 0xC80) != 0x6d50) {
+			release_region (ioaddr, VORTEX_TOTAL_SIZE);
+			continue;
+		}
+
+		/* Check for a product that we support, 3c59{2,7} any rev. */
+		device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
+		if ((device_id & 0xFF00) != 0x5900) {
+			release_region (ioaddr, VORTEX_TOTAL_SIZE);
+			continue;
+		}
+
+		rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
+				   EISA_TBL_OFFSET,
+				   vortex_cards_found);
+		if (rc == 0)
+			vortex_cards_found++;
+		else
+			release_region (ioaddr, VORTEX_TOTAL_SIZE);
 	}
 
 	/* Special code to work-around the Compaq PCI BIOS32 problem. */
 	if (compaq_ioaddr) {
 		vortex_probe1(NULL, compaq_ioaddr, compaq_irq,
-					  compaq_device_id, cards_found++);
-		dev = 0;
+					  compaq_device_id, vortex_cards_found++);
 	}
 
-	return cards_found ? 0 : -ENODEV;
+	return vortex_cards_found - orig_cards_found;
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int __devinit vortex_init_one (struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	int rc;
+
+	rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq,
+			    ent->driver_data, vortex_cards_found);
+	if (rc == 0)
+		vortex_cards_found++;
+	return rc;
 }
-#endif  /* ! Cardbus */
 
 /*
- * vortex_probe1 - initialize one vortex board, after probing
- *		   has located one during bus scan.
+ * Start up the PCI device which is described by *pdev.
+ * Return 0 on success.
  *
- * NOTE: pdev==NULL is a valid condition, indicating
- * non-PCI (generally EISA) bus device
+ * NOTE: pdev can be NULL, for the case of an EISA driver
  */
-static struct net_device *vortex_probe1(struct pci_dev *pdev,
-					long ioaddr, int irq,
-					int chip_idx, int card_idx)
+static int __devinit vortex_probe1(struct pci_dev *pdev,
+				   long ioaddr, int irq,
+				   int chip_idx, int card_idx)
 {
 	struct vortex_private *vp;
 	int option;
 	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
 	int i;
 	struct net_device *dev;
+	static int printed_version = 0;
+	int retval;
 
-	dev = init_etherdev(NULL, 0);
+	if (!printed_version) {
+		printk (KERN_INFO "%s", version);
+		printed_version = 1;
+	}
 
-	printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
-		   dev->name, pci_tbl[chip_idx].name, ioaddr);
+	dev = init_etherdev(NULL, sizeof(*vp));
+	if (!dev) {
+		printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
+		retval = -ENOMEM;
+		goto out;
+	}
+	
+	printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
+	       dev->name,
+	       pdev ? "PCI" : "EISA",
+	       vortex_info_tbl[chip_idx].name,
+	       ioaddr);
 
+	/* private struct aligned and zeroed by init_etherdev */
+	vp = dev->priv;
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->mtu = mtu;
 
-	/* Make certain the descriptor lists are aligned. */
-	vp = kmalloc(sizeof(*vp), GFP_KERNEL);
-
-	memset(vp, 0, sizeof(*vp));
-	dev->priv = vp;
-
-	vp->next_module = root_vortex_dev;
-	root_vortex_dev = dev;
+	/* module list only for EISA devices */
+	if (pdev == NULL) {
+		vp->next_module = root_vortex_eisa_dev;
+		root_vortex_eisa_dev = dev;
+	}
+	
+	/* PCI-only startup logic */
+	if (pdev) {
+		/* EISA resources already marked, so only PCI needs to do this here */
+		if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size,
+				     dev->name)) {
+			printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
+				dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr);
+			retval = -EBUSY;
+			goto free_dev;
+		}
+
+		/* wake up and enable device */		
+		if (pci_enable_device (pdev)) {
+			printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name);
+			retval = -EIO;
+			goto free_region;
+		}
+
+		/* enable bus-mastering if necessary */		
+		if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER)
+			pci_set_master (pdev);
+	}
 
+	vp->lock = SPIN_LOCK_UNLOCKED;
 	vp->chip_id = chip_idx;
-	vp->pci_bus = pdev == NULL ? 0 : pdev->bus->number;
-	vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn;
 	vp->pdev = pdev;
 
 	/* Makes sure rings are at least 16 byte aligned. */
 	vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
 					   + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
 					   &vp->rx_ring_dma);
+	if (vp->rx_ring == 0)
+	{
+		retval = -ENOMEM;
+		goto free_region;
+	}
+
 	vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
 	vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
 
+	/* if we are a PCI driver, we store info in pdev->driver_data
+	 * instead of a module list */	
+	if (pdev)
+		pdev->driver_data = dev;
+
 	/* The lower four bits are the media type. */
 	if (dev->mem_start)
+	{	/*
+		 * AKPM: ewww..  The 'options' param is passed in as the third arg to the
+		 * LILO 'ether=' argument for non-modular use
+		 */
 		option = dev->mem_start;
+	}
 	else if (card_idx < MAX_UNITS)
 		option = options[card_idx];
 	else
 		option = -1;
 
 	if (option >= 0) {
-		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 7;
-		vp->full_duplex = (option & 8) ? 1 : 0;
+		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
+		vp->full_duplex = (option & 0x200) ? 1 : 0;
 		vp->bus_master = (option & 16) ? 1 : 0;
 	} else {
 		vp->media_override = 7;
@@ -797,23 +854,21 @@
 
 	vp->force_fd = vp->full_duplex;
 	vp->options = option;
-
 	/* Read the station address from the EEPROM. */
 	EL3WINDOW(0);
-	for (i = 0; i < 0x40; i++) {
-		int timer;
-#ifdef CARDBUS
-		outw(0x230 + i, ioaddr + Wn0EepromCmd);
-#else
-		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
-#endif
-		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 10; timer >= 0; timer--) {
-			udelay(162);
-			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-				break;
+	{
+		int base = (vortex_info_tbl[chip_idx].drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read;
+		for (i = 0; i < 0x40; i++) {
+			int timer;
+			outw(base + i, ioaddr + Wn0EepromCmd);
+			/* Pause for at least 162 us. for the read to take place. */
+			for (timer = 10; timer >= 0; timer--) {
+				udelay(162);
+				if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+					break;
+			}
+			eeprom[i] = inw(ioaddr + Wn0EepromData);
 		}
-		eeprom[i] = inw(ioaddr + Wn0EepromData);
 	}
 	for (i = 0; i < 0x18; i++)
 		checksum ^= eeprom[i];
@@ -825,11 +880,14 @@
 	}
 	if (checksum != 0x00)
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-
 	for (i = 0; i < 3; i++)
 		((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
 	for (i = 0; i < 6; i++)
 		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+
 #ifdef __sparc__
 	printk(", IRQ %s\n", __irq_itoa(dev->irq));
 #else
@@ -840,15 +898,19 @@
 			   dev->irq);
 #endif
 
-	if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+	if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
 		u32 fn_st_addr;			/* Cardbus function status space */
-		fn_st_addr = pdev == NULL ? 0 : pdev->resource[2].start;
+		fn_st_addr = pci_resource_start (pdev, 2);
 		if (fn_st_addr)
-			vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
-		printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee"
-			   " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base);
-		EL3WINDOW(2);
-		outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
+			vp->cb_fn_base = ioremap(fn_st_addr, 128);
+		printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n",
+			   dev->name, fn_st_addr, vp->cb_fn_base);
+#if 0 /* AKPM */
+		if (vortex_pci_tbl[vp->chip_id].device != 0x5257) {
+			EL3WINDOW(2);
+			outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
+		}
+#endif
 	}
 
 	/* Extract our information from the EEPROM data. */
@@ -857,10 +919,13 @@
 	vp->capabilities = eeprom[16];
 
 	if (vp->info1 & 0x8000)
+	{
 		vp->full_duplex = 1;
+		printk(KERN_INFO "Full duplex capable\n");
+	}
 
 	{
-		char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+		static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 		union wn3_config config;
 		EL3WINDOW(3);
 		vp->available_media = inw(ioaddr + Wn3_Options);
@@ -919,38 +984,65 @@
 		}
 	}
 
+	if (vp->capabilities & CapPwrMgmt)
+		acpi_set_WOL(dev);
+
 	if (vp->capabilities & CapBusMaster) {
 		vp->full_bus_master_tx = 1;
 		printk(KERN_INFO"  Enabling bus-master transmits and %s receives.\n",
 			   (vp->info2 & 1) ? "early" : "whole-frame" );
 		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
+		vp->bus_master = 0;		/* AKPM: vortex only */
 	}
 
-	/* We do a request_region() to register /proc/ioports info. */
-	request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
 	/* The 3c59x-specific entries in the device structure. */
 	dev->open = &vortex_open;
 	dev->hard_start_xmit = &vortex_start_xmit;
-	dev->tx_timeout = &vortex_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT; 
 	dev->stop = &vortex_close;
 	dev->get_stats = &vortex_get_stats;
 	dev->do_ioctl = &vortex_ioctl;
 	dev->set_multicast_list = &set_rx_mode;
+	dev->tx_timeout = &vortex_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	return 0;
 
-	return dev;
+free_region:
+	release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
+free_dev:
+	kfree (dev);
+	printk(KERN_ERR PFX "vortex_probe1 fails.  Returns %d\n", retval);
+out:
+	return retval;
 }
 
-
-static int
-vortex_open(struct net_device *dev)
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+	int i = 2000;
+
+	outw(cmd, dev->base_addr + EL3_CMD);
+	while (--i > 0)
+	{
+		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
+			return;
+	}
+	printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n",
+			   dev->name, cmd, inw(dev->base_addr + EL3_STATUS));
+}
+
+static void
+vortex_up(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	union wn3_config config;
-	int i;
+	int i, device_id;
 
+	if (vp->pdev)
+		device_id = vp->pdev->device;
+	else
+		device_id = 0x5900; /* EISA */
+	
 	/* Before initializing select the active media port. */
 	EL3WINDOW(3);
 	config.i = inl(ioaddr + Wn3_Config);
@@ -961,15 +1053,24 @@
 				   dev->name, vp->media_override,
 				   media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
-	} else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
-			dev->if_port = XCVR_NWAY;
 	} else if (vp->autoselect) {
-		/* Find first available media type, starting with 100baseTx. */
-		dev->if_port = XCVR_100baseTx;
-		while (! (vp->available_media & media_tbl[dev->if_port].mask))
-			dev->if_port = media_tbl[dev->if_port].next;
-	} else
+		if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
+			printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name);
+			dev->if_port = XCVR_NWAY;
+		} else {
+			/* Find first available media type, starting with 100baseTx. */
+			dev->if_port = XCVR_100baseTx;
+			while (! (vp->available_media & media_tbl[dev->if_port].mask))
+				dev->if_port = media_tbl[dev->if_port].next;
+			printk(KERN_INFO "%s: first avaialble mdeia type: %s\n",
+					dev->name,
+					media_tbl[dev->if_port].name);
+		}
+	} else {
 		dev->if_port = vp->default_media;
+		printk(KERN_INFO "%s: using default media %s\n",
+				dev->name, media_tbl[dev->if_port].name);
+	}
 
 	init_timer(&vp->timer);
 	vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
@@ -983,7 +1084,13 @@
 
 	vp->full_duplex = vp->force_fd;
 	config.u.xcvr = dev->if_port;
-	outl(config.i, ioaddr + Wn3_Config);
+	if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
+	{
+		if (vortex_debug > 6)
+			printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n",
+				config.i);
+		outl(config.i, ioaddr + Wn3_Config);
+	}
 
 	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
 		int mii_reg1, mii_reg5;
@@ -1008,31 +1115,18 @@
 		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
 
 	if (vortex_debug > 1) {
-		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
+		printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n",
 			dev->name, config.i);
 	}
 
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
-
-	outw(RxReset, ioaddr + EL3_CMD);
-	/* Wait a few ticks for the RxReset command to complete. */
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
+	wait_for_completion(dev, TxReset);
+	wait_for_completion(dev, RxReset);
 
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
-	/* Use the now-standard shared IRQ implementation. */
-	if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
-		return -EAGAIN;
-	}
-
 	if (vortex_debug > 1) {
 		EL3WINDOW(4);
-		printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
+		printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n",
 			   dev->name, dev->irq, inw(ioaddr + Wn4_Media));
 	}
 
@@ -1042,6 +1136,19 @@
 		outb(dev->dev_addr[i], ioaddr + i);
 	for (; i < 12; i+=2)
 		outw(0, ioaddr + i);
+	if (vp->cb_fn_base) {
+		u_short n = inw(ioaddr + Wn2_ResetOptions);
+#if 0	/* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */
+		/* Inverted LED polarity */
+		if (device_id != 0x5257)
+			n |= 0x0010;
+#endif
+		/* Inverted polarity of MII power bit */
+		if ((device_id == 0x6560) || (device_id == 0x6562) ||
+			(device_id == 0x5257))
+			n |= 0x4000;
+		outw(n, ioaddr + Wn2_ResetOptions);
+	}
 
 	if (dev->if_port == XCVR_10base2)
 		/* Start the thinnet transceiver. We should really wait 50ms...*/
@@ -1073,39 +1180,24 @@
 		/* Initialize the RxEarly register as recommended. */
 		outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
 		outl(0x0020, ioaddr + PktStatus);
-		if (vortex_debug > 2)
-			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			struct sk_buff *skb;
-			vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1));
-			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
-			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
-			skb = dev_alloc_skb(PKT_BUF_SZ);
-			vp->rx_skbuff[i] = skb;
-			if (skb == NULL)
-				break;			/* Bad news!  */
-			skb->dev = dev;			/* Mark as being used by this device. */
-			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
-		}
-		/* Wrap the ring. */
-		vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
-		outl(vp->rx_ring_dma, ioaddr + UpListPtr);
+		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
 	}
 	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
 		dev->hard_start_xmit = &boomerang_start_xmit;
 		vp->cur_tx = vp->dirty_tx = 0;
 		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
-		/* Clear the Tx ring. */
+		/* Clear the Rx, Tx rings. */
+		for (i = 0; i < RX_RING_SIZE; i++)	/* AKPM: this is done in vortex_open, too */
+			vp->rx_ring[i].status = 0;
 		for (i = 0; i < TX_RING_SIZE; i++)
 			vp->tx_skbuff[i] = 0;
 		outl(0, ioaddr + DownListPtr);
 	}
-	/* Set reciever mode: presumably accept b-case and phys addr only. */
+	/* Set receiver mode: presumably accept b-case and phys addr only. */
 	set_rx_mode(dev);
 	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
-	vp->in_interrupt = 0;
+	netif_start_queue (dev);
 
 	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
 	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
@@ -1114,7 +1206,8 @@
 		(vp->full_bus_master_tx ? DownComplete : TxAvailable) |
 		(vp->full_bus_master_rx ? UpComplete : RxComplete) |
 		(vp->bus_master ? DMADone : 0);
-	vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
+	vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable |
+		(vp->full_bus_master_rx ? 0 : RxComplete) |
 		StatsFull | HostError | TxComplete | IntReq
 		| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
 	outw(vp->status_enable, ioaddr + EL3_CMD);
@@ -1125,11 +1218,55 @@
 	if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
 		writel(0x8000, vp->cb_fn_base + 4);
 
-	netif_start_queue(dev);
+	/* AKPM: unjam the 3CCFE575CT */
+	wait_for_completion(dev, TxReset);
+	outw(TxEnable, ioaddr + EL3_CMD);
+}
+
+static int
+vortex_open(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int i;
+	int retval;
 
 	MOD_INC_USE_COUNT;
 
+	/* Use the now-standard shared IRQ implementation. */
+	if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt,
+					SA_SHIRQ, dev->name, dev)) {
+		retval = -EAGAIN;
+		goto out;
+	}
+
+	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+		if (vortex_debug > 2)
+			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			struct sk_buff *skb;
+			vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1]));
+			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
+			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			vp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
+		}
+		/* Wrap the ring. */
+		vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
+	}
+
+	vortex_up(dev);
+	vp->open = 1;
 	return 0;
+out:
+	MOD_DEC_USE_COUNT;
+	if (vortex_debug > 1)
+		printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval);
+	return retval;
 }
 
 static void vortex_timer(unsigned long data)
@@ -1137,7 +1274,7 @@
 	struct net_device *dev = (struct net_device *)data;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int next_tick = 0;
+	int next_tick = 60*HZ;
 	int ok = 0;
 	int media_status, mii_status, old_window;
 
@@ -1152,43 +1289,50 @@
 	switch (dev->if_port) {
 	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
 		if (media_status & Media_LnkBeat) {
-		  ok = 1;
-		  if (vortex_debug > 1)
-			printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
-				   dev->name, media_tbl[dev->if_port].name, media_status);
+			ok = 1;
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
+					   dev->name, media_tbl[dev->if_port].name, media_status);
 		} else if (vortex_debug > 1)
-		  printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
+			printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
 		break;
-	  case XCVR_MII: case XCVR_NWAY:
-		  mii_status = mdio_read(ioaddr, vp->phys[0], 1);
-		  ok = 1;
-		  if (debug > 1)
-			  printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
-					 dev->name, mii_status);
-		  if (mii_status & 0x0004) {
-			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-			  if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
-				  int duplex = (mii_reg5&0x0100) ||
-					  (mii_reg5 & 0x01C0) == 0x0040;
-				  if (vp->full_duplex != duplex) {
-					  vp->full_duplex = duplex;
-					  printk(KERN_INFO "%s: Setting %s-duplex based on MII "
-							 "#%d link partner capability of %4.4x.\n",
-							 dev->name, vp->full_duplex ? "full" : "half",
-							 vp->phys[0], mii_reg5);
-					  /* Set the full-duplex bit. */
-					  outb((vp->full_duplex ? 0x20 : 0) |
-						   (dev->mtu > 1500 ? 0x40 : 0),
-						   ioaddr + Wn3_MAC_Ctrl);
-				  }
-				  next_tick = 60*HZ;
-			  }
-		  }
-		  break;
+	case XCVR_MII: case XCVR_NWAY:
+		{
+			unsigned long flags;
+			spin_lock_irqsave(&vp->lock, flags);	/* AKPM: protect mdio state */
+
+			mii_status = mdio_read(ioaddr, vp->phys[0], 1);
+			ok = 1;
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
+					dev->name, mii_status);
+			if (mii_status & 0x0004) {
+				int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+				if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
+					int duplex = (mii_reg5&0x0100) ||
+						(mii_reg5 & 0x01C0) == 0x0040;
+					if (vp->full_duplex != duplex) {
+						vp->full_duplex = duplex;
+						printk(KERN_INFO "%s: Setting %s-duplex based on MII "
+							"#%d link partner capability of %4.4x.\n",
+							dev->name, vp->full_duplex ? "full" : "half",
+							vp->phys[0], mii_reg5);
+						/* Set the full-duplex bit. */
+						EL3WINDOW(3);	/* AKPM: this was missing from 2.3.99 3c59x.c! */
+						outb((vp->full_duplex ? 0x20 : 0) |
+							(dev->mtu > 1500 ? 0x40 : 0),
+							ioaddr + Wn3_MAC_Ctrl);
+					}
+					next_tick = 60*HZ;
+				}
+			}
+			spin_unlock_irqrestore(&vp->lock, flags);
+		}
+		break;
 	  default:					/* Other media types handled by Tx timeouts. */
 		if (vortex_debug > 1)
-		  printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
+		  printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n",
 				 dev->name, media_tbl[dev->if_port].name, media_status);
 		ok = 1;
 	}
@@ -1205,11 +1349,11 @@
 				   "%s port.\n",
 				   dev->name, media_tbl[dev->if_port].name);
 		} else {
-		  if (vortex_debug > 1)
-			printk(KERN_DEBUG "%s: Media selection failed, now trying "
-				   "%s port.\n",
-				   dev->name, media_tbl[dev->if_port].name);
-		  next_tick = media_tbl[dev->if_port].wait;
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: Media selection failed, now trying "
+					   "%s port.\n",
+					   dev->name, media_tbl[dev->if_port].name);
+			next_tick = media_tbl[dev->if_port].wait;
 		}
 		outw((media_status & ~(Media_10TP|Media_SQE)) |
 			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
@@ -1225,14 +1369,14 @@
 	EL3WINDOW(old_window);
 	enable_irq(dev->irq);
 
-	if (vortex_debug > 2)
+	if (vortex_debug > 1)
 	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
-	if (next_tick) {
-		vp->timer.expires = RUN_AT(next_tick);
-		add_timer(&vp->timer);
-	}
+	vp->timer.expires = RUN_AT(next_tick);
+	add_timer(&vp->timer);
+	if (vp->deferred)
+		outw(FakeIntr, ioaddr + EL3_CMD);
 	return;
 }
 
@@ -1240,7 +1384,6 @@
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int j;
 
 	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 		   dev->name, inb(ioaddr + TxStatus),
@@ -1253,30 +1396,41 @@
 		printk(KERN_ERR "%s: Interrupt posted but not delivered --"
 			   " IRQ blocked by another device?\n", dev->name);
 		/* Bad idea here.. but we might as well handle a few events. */
-		vortex_interrupt(dev->irq, dev, 0);
+		{
+			/*
+			 * AKPM: block interrupts because vortex_interrupt
+			 * does a bare spin_lock()
+			 */
+			unsigned long flags;
+			local_irq_save(flags);
+			if (vp->full_bus_master_tx)
+				boomerang_interrupt(dev->irq, dev, 0);
+			else
+				vortex_interrupt(dev->irq, dev, 0);
+			local_irq_restore(flags);
+		}
 	}
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (j = 200; j >= 0 ; j--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
 
-#if ! defined(final_version)
-	if (vp->full_bus_master_tx) {
-		int i;
-		printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
-			   "current %d.\n",
-			   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
-		printk(KERN_DEBUG "  Transmit list %8.8x vs. %p.\n",
-			   inl(ioaddr + DownListPtr),
-			   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
-		for (i = 0; i < TX_RING_SIZE; i++) {
-			printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
-				   &vp->tx_ring[i],
-				   le32_to_cpu(vp->tx_ring[i].length),
-				   le32_to_cpu(vp->tx_ring[i].status));
+	if (vortex_debug > 0) {
+		if (vp->full_bus_master_tx) {
+			int i;
+			printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
+				   "current %d.\n",
+				   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+			printk(KERN_DEBUG "  Transmit list %8.8x vs. %p.\n",
+				   inl(ioaddr + DownListPtr),
+				   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+			for (i = 0; i < TX_RING_SIZE; i++) {
+				printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
+					   &vp->tx_ring[i],
+					   le32_to_cpu(vp->tx_ring[i].length),
+					   le32_to_cpu(vp->tx_ring[i].status));
+			}
 		}
 	}
-#endif
+
+	wait_for_completion(dev, TxReset);
+
 	vp->stats.tx_errors++;
 	if (vp->full_bus_master_tx) {
 		if (vortex_debug > 0)
@@ -1287,8 +1441,10 @@
 				 ioaddr + DownListPtr);
 		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
 			vp->tx_full = 0;
-			netif_wake_queue(dev);
+			netif_start_queue (dev);
 		}
+		if (vp->tx_full)
+			netif_stop_queue (dev);
 		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
 		outw(DownUnstall, ioaddr + EL3_CMD);
 	} else
@@ -1312,7 +1468,9 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int do_tx_reset = 0;
-	int i;
+
+	if (vortex_debug > 2)
+		printk(KERN_DEBUG "%s: vortex_error(), status=0x%x\n", dev->name, status);
 
 	if (status & TxComplete) {			/* Really "TxError" for us. */
 		unsigned char tx_status = inb(ioaddr + TxStatus);
@@ -1358,25 +1516,18 @@
 		u16 fifo_diag;
 		EL3WINDOW(4);
 		fifo_diag = inw(ioaddr + Wn4_FIFODiag);
-		if (vortex_debug > 0)
-			printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
-				   dev->name, fifo_diag);
+		printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
+			   dev->name, fifo_diag);
 		/* Adapter failure requires Tx/Rx reset and reinit. */
 		if (vp->full_bus_master_tx) {
-			outw(TotalReset | 0xff, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
-			/* Re-enable the receiver. */
-			outw(RxEnable, ioaddr + EL3_CMD);
-			outw(TxEnable, ioaddr + EL3_CMD);
+			/* In this case, blow the card away */
+			vortex_down(dev);
+			wait_for_completion(dev, TotalReset | 0xff);
+			vortex_up(dev);
 		} else if (fifo_diag & 0x0400)
 			do_tx_reset = 1;
 		if (fifo_diag & 0x3000) {
-			outw(RxReset, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
+			wait_for_completion(dev, RxReset);
 			/* Set the Rx filter to the current state. */
 			set_rx_mode(dev);
 			outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
@@ -1384,40 +1535,37 @@
 		}
 	}
 	if (do_tx_reset) {
-		int j;
-		outw(TxReset, ioaddr + EL3_CMD);
-		for (j = 200; j >= 0 ; j--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, TxReset);
 		outw(TxEnable, ioaddr + EL3_CMD);
 	}
 
 }
 
-
 static int
 vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	netif_stop_queue(dev);
-
+	netif_stop_queue (dev);
+	
 	/* Put out the doubleword header... */
 	outl(skb->len, ioaddr + TX_FIFO);
 	if (vp->bus_master) {
 		/* Set the bus-master controller to transfer the packet. */
 		int len = (skb->len + 3) & ~3;
-		outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr);
+		outl(	vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE),
+				ioaddr + Wn7_MasterAddr);
 		outw(len, ioaddr + Wn7_MasterLen);
 		vp->tx_skb = skb;
 		outw(StartDMADown, ioaddr + EL3_CMD);
+		/* dev->tbusy will be cleared at the DMADone interrupt. */
 	} else {
 		/* ... and the packet rounded to a doubleword. */
 		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-		DEV_FREE_SKB(skb);
+		dev_kfree_skb (skb);
 		if (inw(ioaddr + TxFree) > 1536) {
-			netif_wake_queue(dev);
+			netif_start_queue (dev);
 		} else
 			/* Interrupt us when the FIFO has room for max-sized packet. */
 			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1438,18 +1586,13 @@
 				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
 				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
 				if (tx_status & 0x30) {
-					int j;
-					outw(TxReset, ioaddr + EL3_CMD);
-					for (j = 200; j >= 0 ; j--)
-						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-							break;
+					wait_for_completion(dev, TxReset);
 				}
 				outw(TxEnable, ioaddr + EL3_CMD);
 			}
 			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
 		}
 	}
-	vp->stats.tx_bytes += skb->len;
 	return 0;
 }
 
@@ -1459,21 +1602,22 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	netif_stop_queue(dev);
+	if (vortex_debug > 6)
+		printk(KERN_DEBUG "boomerang_start_xmit()\n");
 
-	if (1) {
+	netif_stop_queue (dev);
+	{
 		/* Calculate the next Tx descriptor entry. */
 		int entry = vp->cur_tx % TX_RING_SIZE;
 		struct boom_tx_desc *prev_entry =
 			&vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
 		unsigned long flags;
-		int i;
 
 		if (vortex_debug > 3)
 			printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
 				   dev->name, vp->cur_tx);
 		if (vp->tx_full) {
-			if (vortex_debug >0)
+			if (vortex_debug > 0)
 				printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
 					   dev->name);
 			return 1;
@@ -1484,37 +1628,40 @@
 		vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
 		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
 
-		/* Hmm... And some poor people try to use it on SMP machines 8) */
-		save_flags(flags);
-		cli();
-		outw(DownStall, ioaddr + EL3_CMD);
+		spin_lock_irqsave(&vp->lock, flags);
 		/* Wait for the stall to complete. */
-		for (i = 600; i >= 0 ; i--)
-			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
-				break;
+		wait_for_completion(dev, DownStall);
 		prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc));
 		if (inl(ioaddr + DownListPtr) == 0) {
 			outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr);
 			queued_packet++;
 		}
-		outw(DownUnstall, ioaddr + EL3_CMD);
-		restore_flags(flags);
 
 		vp->cur_tx++;
 		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
 			vp->tx_full = 1;
+			netif_stop_queue (dev);
 		} else {					/* Clear previous interrupt enable. */
+#if defined(tx_interrupt_mitigation)
 			prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
-			netif_wake_queue(dev);
+#endif
+			netif_start_queue (dev);
 		}
+		outw(DownUnstall, ioaddr + EL3_CMD);
+		spin_unlock_irqrestore(&vp->lock, flags);
 		dev->trans_start = jiffies;
-		vp->stats.tx_bytes += skb->len;
 		return 0;
 	}
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
+
+/*
+ * This is the ISR for the vortex series chips.
+ * full_bus_master_tx == 0 && full_bus_master_rx == 0
+ */
+
 static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
@@ -1523,10 +1670,23 @@
 	int latency, status;
 	int work_done = max_interrupt_work;
 
+	spin_lock(&vp->lock);
+	
 	ioaddr = dev->base_addr;
 	latency = inb(ioaddr + Timer);
 	status = inw(ioaddr + EL3_STATUS);
 
+	if (vortex_debug > 6)
+		printk("AKPM: vortex_interrupt. status=0x%4x\n", status);
+
+	if (status & IntReq) {
+		status |= vp->deferred;
+		vp->deferred = 0;
+	}
+
+	if (status == 0xffff)		/* AKPM: h/w no longer present (hotplug)? */
+		goto handler_exit;
+
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
 			   dev->name, status, latency);
@@ -1536,22 +1696,117 @@
 					   dev->name, status);
 		if (status & RxComplete)
 			vortex_rx(dev);
-		if (status & UpComplete) {
-			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
-			boomerang_rx(dev);
-		}
 
 		if (status & TxAvailable) {
 			if (vortex_debug > 5)
 				printk(KERN_DEBUG "	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue(dev);
+			netif_wake_queue (dev);
+		}
+
+		if (status & DMADone) {
+			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
+				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
+				pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
+				if (inw(ioaddr + TxFree) > 1536) {
+					netif_wake_queue (dev);
+				} else { /* Interrupt when FIFO has room for max-sized packet. */
+					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+					netif_stop_queue (dev);		/* AKPM: This is new */
+				}
+			}
+		}
+		/* Check for all uncommon interrupts at once. */
+		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
+			if (status == 0xffff)
+				break;
+			vortex_error(dev, status);
+		}
+
+		if (--work_done < 0) {
+			printk(KERN_WARNING "%s: Too much work in interrupt, status "
+				   "%4.4x.\n", dev->name, status);
+			/* Disable all pending interrupts. */
+			do {
+				vp->deferred |= status;
+				outw(SetStatusEnb | (~vp->deferred & vp->status_enable),
+					 ioaddr + EL3_CMD);
+				outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
+			} while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
+			/* The timer will reenable interrupts. */
+			del_timer(&vp->timer);
+			vp->timer.expires = RUN_AT(1);
+			add_timer(&vp->timer);
+			break;
+		}
+		/* Acknowledge the IRQ. */
+		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+		if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
+			writel(0x8000, vp->cb_fn_base + 4);
+
+	} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+
+	if (vortex_debug > 4)
+		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
+			   dev->name, status);
+handler_exit:
+	spin_unlock(&vp->lock);
+}
+
+/*
+ * This is the ISR for the boomerang series chips.
+ * full_bus_master_tx == 1 && full_bus_master_rx == 1
+ */
+
+static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr;
+	int latency, status;
+	int work_done = max_interrupt_work;
+
+	spin_lock(&vp->lock);
+	
+	ioaddr = dev->base_addr;
+	latency = inb(ioaddr + Timer);
+	status = inw(ioaddr + EL3_STATUS);
+
+	if (vortex_debug > 6)
+		printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status);
+
+	if (status & IntReq) {
+		status |= vp->deferred;
+		vp->deferred = 0;
+	}
+
+	if (status == 0xffff)		/* AKPM: h/w no longer present (hotplug)? */
+	{
+		if (vortex_debug > 1)
+			printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n");
+		goto handler_exit;
+	}
+
+	if (vortex_debug > 4)
+		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+			   dev->name, status, latency);
+	do {
+		if (vortex_debug > 5)
+				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
+					   dev->name, status);
+		if (status & UpComplete) {
+			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+			if (vortex_debug > 5)
+				printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n");
+			boomerang_rx(dev);
 		}
 
 		if (status & DownComplete) {
 			unsigned int dirty_tx = vp->dirty_tx;
 
+			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
 			while (vp->cur_tx - dirty_tx > 0) {
 				int entry = dirty_tx % TX_RING_SIZE;
 				if (inl(ioaddr + DownListPtr) ==
@@ -1560,31 +1815,27 @@
 				if (vp->tx_skbuff[entry]) {
 					struct sk_buff *skb = vp->tx_skbuff[entry];
 					
-					pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
-					dev_kfree_skb_irq(vp->tx_skbuff[entry]);
+					pci_unmap_single(vp->pdev,
+						le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
+					dev_kfree_skb_irq(skb);
 					vp->tx_skbuff[entry] = 0;
+				} else {
+					printk(KERN_DEBUG "boomerang_interrupt: no skb!\n");
 				}
 				/* vp->stats.tx_packets++;  Counted below. */
 				dirty_tx++;
 			}
 			vp->dirty_tx = dirty_tx;
-			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
 			if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
-				vp->tx_full= 0;
-				netif_wake_queue(dev);
-			}
-		}
-		if (status & DMADone) {
-			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
-				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE);
-				dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
-				if (inw(ioaddr + TxFree) > 1536) {
-					netif_wake_queue(dev);
-				} else /* Interrupt when FIFO has room for max-sized packet. */
-					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+				if (vortex_debug > 6)
+					printk(KERN_DEBUG "boomerang_interrupt: clearing tx_full\n");
+				vp->tx_full = 0;
+				netif_wake_queue (dev);
 			}
 		}
+		if (vp->tx_full)
+			netif_stop_queue (dev);
+
 		/* Check for all uncommon interrupts at once. */
 		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
 			if (status == 0xffff)
@@ -1593,19 +1844,20 @@
 		}
 
 		if (--work_done < 0) {
-			if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) {
-				/* Just ack these and return. */
-				outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD);
-			} else {
-				printk(KERN_WARNING "%s: Too much work in interrupt, status "
-					   "%4.4x.  Temporarily disabling functions (%4.4x).\n",
-					   dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
-				/* Disable all pending interrupts. */
-				outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
-				outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
-				/* The timer will reenable interrupts. */
-				break;
-			}
+			printk(KERN_WARNING "%s: Too much work in interrupt, status "
+				   "%4.4x.\n", dev->name, status);
+			/* Disable all pending interrupts. */
+			do {
+				vp->deferred |= status;
+				outw(SetStatusEnb | (~vp->deferred & vp->status_enable),
+					 ioaddr + EL3_CMD);
+				outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
+			} while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
+			/* The timer will reenable interrupts. */
+			del_timer(&vp->timer);
+			vp->timer.expires = RUN_AT(1);
+			add_timer(&vp->timer);
+			break;
 		}
 		/* Acknowledge the IRQ. */
 		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
@@ -1617,8 +1869,8 @@
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
-
-	return;
+handler_exit:
+	spin_unlock(&vp->lock);
 }
 
 static int vortex_rx(struct net_device *dev)
@@ -1629,7 +1881,7 @@
 	short rx_status;
 
 	if (vortex_debug > 5)
-		printk(KERN_DEBUG"   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+		printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
 	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
 		if (rx_status & 0x4000) { /* Error, update stats. */
@@ -1674,22 +1926,17 @@
 				netif_rx(skb);
 				dev->last_rx = jiffies;
 				vp->stats.rx_packets++;
-				vp->stats.rx_bytes += skb->len;
 				/* Wait a limited time to go to next packet. */
 				for (i = 200; i >= 0; i--)
 					if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 						break;
 				continue;
-			} else if (vortex_debug)
+			} else if (vortex_debug > 0)
 				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
 					   "size %d.\n", dev->name, pkt_len);
 		}
-		outw(RxDiscard, ioaddr + EL3_CMD);
 		vp->stats.rx_dropped++;
-		/* Wait a limited time to skip this packet. */
-		for (i = 200; i >= 0; i--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, RxDiscard);
 	}
 
 	return 0;
@@ -1705,7 +1952,7 @@
 	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
 
 	if (vortex_debug > 5)
-		printk(KERN_DEBUG "  In boomerang_rx(), status %4.4x, rx_status "
+		printk(KERN_DEBUG "boomerang_rx(): status %4.4x, rx_status "
 			   "%4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
 	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
@@ -1787,22 +2034,13 @@
 	return 0;
 }
 
-static int
-vortex_close(struct net_device *dev)
+static void
+vortex_down(struct net_device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int i;
-
-	netif_stop_queue(dev);
 
-	if (vortex_debug > 1) {
-		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
-			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
-		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
-			   " tx_queued %d Rx pre-checksummed %d.\n",
-			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
-	}
+	netif_stop_queue (dev);
 
 	del_timer(&vp->timer);
 
@@ -1817,34 +2055,60 @@
 		/* Turn off thinnet power.  Green! */
 		outw(StopCoax, ioaddr + EL3_CMD);
 
-	free_irq(dev->irq, dev);
-
 	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
 
 	update_stats(ioaddr, dev);
-	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+	if (vp->full_bus_master_rx)
 		outl(0, ioaddr + UpListPtr);
+	if (vp->full_bus_master_tx)
+		outl(0, ioaddr + DownListPtr);
+
+	if (vp->capabilities & CapPwrMgmt)
+		acpi_set_WOL(dev);
+}
+
+static int
+vortex_close(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	if (netif_device_present(dev))
+		vortex_down(dev);
+
+	if (vortex_debug > 1) {
+		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
+			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
+		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
+			   " tx_queued %d Rx pre-checksummed %d.\n",
+			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
+	}
+
+	free_irq(dev->irq, dev);
+
+	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
 		for (i = 0; i < RX_RING_SIZE; i++)
 			if (vp->rx_skbuff[i]) {
-				pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-				DEV_FREE_SKB(vp->rx_skbuff[i]);
+				pci_unmap_single(	vp->pdev, le32_to_cpu(vp->rx_ring[i].addr),
+									PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				dev_kfree_skb(vp->rx_skbuff[i]);
 				vp->rx_skbuff[i] = 0;
 			}
 	}
 	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
-		outl(0, ioaddr + DownListPtr);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			if (vp->tx_skbuff[i]) {
 				struct sk_buff *skb = vp->tx_skbuff[i];
 
 				pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
-				DEV_FREE_SKB(skb);
+				dev_kfree_skb(skb);
 				vp->tx_skbuff[i] = 0;
 			}
 	}
 
 	MOD_DEC_USE_COUNT;
-
+	vp->open = 0;
 	return 0;
 }
 
@@ -1853,11 +2117,10 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
 
-	if (netif_running(dev)) {
-		save_flags(flags);
-		cli();
+	if (netif_device_present(dev)) {	/* AKPM: Used to be netif_running */
+		spin_lock_irqsave (&vp->lock, flags);
 		update_stats(dev->base_addr, dev);
-		restore_flags(flags);
+		spin_unlock_irqrestore (&vp->lock, flags);
 	}
 	return &vp->stats;
 }
@@ -1872,7 +2135,10 @@
 static void update_stats(long ioaddr, struct net_device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int old_window = inw(ioaddr + EL3_CMD);
 
+	if (old_window == 0xffff)	/* Chip suspended or ejected. */
+		return;
 	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
 	/* Switch to the stats window, and read everything. */
 	EL3WINDOW(6);
@@ -1889,14 +2155,21 @@
 	/* Don't bother with register 9, an extension of registers 6&7.
 	   If we do use the 6&7 values the atomic update assumption above
 	   is invalid. */
-	inw(ioaddr + 10);	/* Total Rx and Tx octets. */
-	inw(ioaddr + 12);
+	vp->stats.rx_bytes += inw(ioaddr + 10);
+	vp->stats.tx_bytes += inw(ioaddr + 12);
 	/* New: On the Vortex we must also clear the BadSSD counter. */
 	EL3WINDOW(4);
 	inb(ioaddr + 12);
 
+	{
+		u8 up = inb(ioaddr + 13);
+		vp->stats.rx_bytes += (up & 0x0f) << 16;
+		vp->stats.tx_bytes += (up & 0xf0) << 12;
+	}
+
 	/* We change back to window 7 (not 1) with the Vortex. */
-	EL3WINDOW(7);
+	/* AKPM: the previous comment is obsolete - we switch back to the old window */
+	EL3WINDOW(old_window >> 13);
 	return;
 }
 
@@ -1906,6 +2179,10 @@
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = vp->phys[0] & 0x1f;
+	int retval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vp->lock, flags);
 
 	switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
@@ -1913,16 +2190,24 @@
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		EL3WINDOW(4);
 		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-		return 0;
+		retval = 0;
+		break;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		EL3WINDOW(4);
-		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-		return 0;
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+		} else {
+			EL3WINDOW(4);
+			mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+			retval = 0;
+		}
+		break;
 	default:
-		return -EOPNOTSUPP;
+		retval = -EOPNOTSUPP;
+		break;
 	}
+
+	spin_unlock_irqrestore(&vp->lock, flags);
+	return retval;
 }
 
 /* Pre-Cyclone chips have no documented multicast filter, so the only
@@ -1945,7 +2230,6 @@
 	outw(new_mode, ioaddr + EL3_CMD);
 }
 
-
 /* MII transceiver control section.
    Read and write the MII registers using software-generated serial
    MDIO protocol.  See the MII specifications or DP83840A data sheet
@@ -2004,11 +2288,7 @@
 		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
 		mdio_delay();
 	}
-#if 0
-	return (retval>>1) & 0x1ffff;
-#else
 	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
-#endif
 }
 
 static void mdio_write(long ioaddr, int phy_id, int location, int value)
@@ -2038,42 +2318,131 @@
 
 	return;
 }
+
+/* ACPI: Advanced Configuration and Power Interface. */
+/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
+static void acpi_set_WOL(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	/* AKPM: This kills the 905 */
+	if (vortex_debug > 0) {
+		printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n");
+	}
+	return;
+
+	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+	EL3WINDOW(7);
+	outw(2, ioaddr + 0x0c);
+	/* The RxFilter must accept the WOL frames. */
+	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+	outw(RxEnable, ioaddr + EL3_CMD);
+	/* Change the power state to D3; RxEnable doesn't take effect. */
+	pci_write_config_word(vp->pdev, 0xe0, 0x8103);
+}
 
 
-static void __exit vortex_cleanup_module (void)
+static void __devexit vortex_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *next_dev;
+	struct net_device *dev = pdev->driver_data;
+	struct vortex_private *vp;
 
-#ifdef CARDBUS
-	unregister_driver(&vortex_ops);
-#endif
+	if (!dev)
+		return;
+
+	vp = (void *)(dev->priv);
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (root_vortex_dev) {
-		struct vortex_private *vp=(void *)(root_vortex_dev->priv);
-		next_dev = vp->next_module;
-		unregister_netdev(root_vortex_dev);
-		outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
-		release_region(root_vortex_dev->base_addr,
-					   pci_tbl[vp->chip_id].io_size);
-		kfree(root_vortex_dev);
-		pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
-					    + sizeof(struct boom_tx_desc) * TX_RING_SIZE
-					    + 15, vp->rx_ring, vp->rx_ring_dma);
-		kfree(vp);
-		root_vortex_dev = next_dev;
+	unregister_netdev(dev);
+	outw(TotalReset, dev->base_addr + EL3_CMD);
+	release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size);
+	kfree(dev);
+}
+
+
+static struct pci_driver vortex_driver = {
+	name:		"3c575_cb",
+	probe:		vortex_init_one,
+	remove:		vortex_remove_one,
+	suspend:	vortex_suspend,
+	resume:		vortex_resume,
+	id_table:	vortex_pci_tbl,
+};
+
+
+static int vortex_have_pci = 0;
+static int vortex_have_eisa = 0;
+
+
+static int __init vortex_init (void)
+{
+	int rc;
+	
+	MOD_INC_USE_COUNT;
+
+	rc = pci_module_init (&vortex_driver);
+	if (rc < 0)
+		goto out;
+
+	if (rc >= 0)	/* AKPM: had "> 0" */
+		vortex_have_pci = 1;
+
+	rc = vortex_eisa_init ();
+	if (rc < 0)
+		goto out;
+
+	if (rc > 0)
+		vortex_have_eisa = 1;
+
+out:
+	MOD_DEC_USE_COUNT;
+	return rc;
+}
+
+
+static void __exit vortex_eisa_cleanup (void)
+{
+	struct net_device *dev, *tmp;
+	struct vortex_private *vp;
+	long ioaddr;
+
+	dev = root_vortex_eisa_dev;
+
+	while (dev) {
+		vp = dev->priv;
+		ioaddr = dev->base_addr;
+
+		unregister_netdev (dev);
+		outw (TotalReset, ioaddr + EL3_CMD);
+		release_region (ioaddr, VORTEX_TOTAL_SIZE);
+
+		tmp = dev;
+		dev = vp->next_module;
+
+		kfree (tmp);
 	}
 }
 
-module_init(vortex_init_module);
-module_exit(vortex_cleanup_module);
+
+static void __exit vortex_cleanup (void)
+{
+	if (vortex_have_pci)
+		pci_unregister_driver (&vortex_driver);
+	if (vortex_have_eisa)
+		vortex_eisa_cleanup ();
+}
 
 
+module_init(vortex_init);
+module_exit(vortex_cleanup);
+
+
+
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
+ *  cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.3.99-pre5/linux/drivers/net/8139too.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/8139too.c	Fri Apr 14 09:37:10 2000
@@ -439,7 +439,7 @@
 	u8 tmp8;
 	int rc;
 	u32 pio_start, pio_end, pio_flags, pio_len;
-	u32 mmio_start, mmio_end, mmio_flags, mmio_len;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
 
 	DPRINTK ("ENTER\n");
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/82596.c linux/drivers/net/82596.c
--- v2.3.99-pre5/linux/drivers/net/82596.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/82596.c	Tue Apr 25 17:38:33 2000
@@ -40,7 +40,7 @@
 
  */
 
-static const char *version = "82596.c:v1.0 15/07/98\n";
+static const char *version = "82596.c $Revision: 1.4 $\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -63,6 +63,32 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT	0x0001
+#define DEB_PROBE	0x0002
+#define DEB_SERIOUS	0x0004
+#define DEB_ERRORS	0x0008
+#define DEB_MULTI	0x0010
+#define DEB_TDR		0x0020
+#define DEB_OPEN	0x0040
+#define DEB_RESET	0x0080
+#define DEB_ADDCMD	0x0100
+#define DEB_STATUS	0x0200
+#define DEB_STARTTX	0x0400
+#define DEB_RXADDR	0x0800
+#define DEB_TXADDR	0x1000
+#define DEB_RXFRAME	0x2000
+#define DEB_INTS	0x4000
+#define DEB_STRUCT	0x8000
+#define DEB_ANY		0xffff
+
+
+#define DEB(x,y)	if (i596_debug & (x)) y
+
 
 #if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
 #define ENABLE_MVME16x_NET
@@ -97,13 +123,13 @@
 #define ISCP_BUSY	0x00010000
 #define MACH_IS_APRICOT	0
 #else
-#define WSWAPrfd(x)	x
-#define WSWAPrbd(x)	((struct i596_rbd *)(x))
-#define WSWAPiscp(x)	((struct i596_iscp *)(x))
-#define WSWAPscb(x)	((struct i596_scb *)(x))
-#define WSWAPcmd(x)	x
-#define WSWAPtbd(x)	x
-#define WSWAPchar(x)	((char *)(x))
+#define WSWAPrfd(x)     ((struct i596_rfd *)(x))
+#define WSWAPrbd(x)     ((struct i596_rbd *)(x))
+#define WSWAPiscp(x)    ((struct i596_iscp *)(x))
+#define WSWAPscb(x)     ((struct i596_scb *)(x))
+#define WSWAPcmd(x)     ((struct i596_cmd *)(x))
+#define WSWAPtbd(x)     ((struct i596_tbd *)(x))
+#define WSWAPchar(x)    ((char *)(x))
 #define ISCP_BUSY	0x0001
 #define MACH_IS_APRICOT	1
 #endif
@@ -119,13 +145,12 @@
 #define PORT_ALTSCP		0x02	/* alternate SCB address */
 #define PORT_ALTDUMP		0x03	/* Alternate DUMP address */
 
-#define I82596_DEBUG 1
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_PARM(i596_debug, "i");
 
-#ifdef I82596_DEBUG
-int i596_debug = I82596_DEBUG;
-#else
-int i596_debug = 1;
-#endif
 
 /* Copy frames shorter than rx_copybreak, otherwise pass on up in
  * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
@@ -137,7 +162,7 @@
 
 #define I596_TOTAL_SIZE 17
 
-#define I596_NULL -1
+#define I596_NULL ((void *)0xffffffff)
 
 #define CMD_EOL		0x8000	/* The last command of the list, stop. */
 #define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
@@ -164,7 +189,8 @@
 #define	 RX_SUSPEND	0x0030
 #define	 RX_ABORT	0x0040
 
-#define	 TX_TIMEOUT	5
+#define TX_TIMEOUT	5
+
 
 struct i596_reg {
 	unsigned short porthi;
@@ -172,12 +198,6 @@
 	unsigned long ca;
 };
 
-struct i596_cmd {
-	unsigned short status;
-	unsigned short command;
-	struct i596_cmd *next;
-};
-
 #define EOF		0x8000
 #define SIZE_MASK	0x3fff
 
@@ -188,6 +208,23 @@
 	char *data;
 };
 
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596.  The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next.  It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+	struct i596_cmd *v_next;	/* Address from CPUs viewpoint */
+	unsigned short status;
+	unsigned short command;
+	struct i596_cmd *b_next;	/* Address from i596 viewpoint */
+};
+
 struct tx_cmd {
 	struct i596_cmd cmd;
 	struct i596_tbd *tbd;
@@ -196,26 +233,53 @@
 	struct sk_buff *skb;	/* So we can free it after tx */
 };
 
+struct tdr_cmd {
+	struct i596_cmd cmd;
+	unsigned short status;
+	unsigned short pad;
+};
+
+struct mc_cmd {
+	struct i596_cmd cmd;
+	short mc_cnt;
+	char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+	struct i596_cmd cmd;
+	char eth_addr[8];
+};
+
+struct cf_cmd {
+	struct i596_cmd cmd;
+	char i596_config[16];
+};
+
 struct i596_rfd {
 	unsigned short stat;
 	unsigned short cmd;
-	struct i596_rfd *next;
+	struct i596_rfd *b_next;	/* Address from i596 viewpoint */
 	struct i596_rbd *rbd;
 	unsigned short count;
 	unsigned short size;
+	struct i596_rfd *v_next;	/* Address from CPUs viewpoint */
+	struct i596_rfd *v_prev;
 };
 
 struct i596_rbd {
     unsigned short count;
     unsigned short zero1;
-    struct i596_rbd *next;
-    char *data;
+    struct i596_rbd *b_next;
+    unsigned char *b_data;		/* Address from i596 viewpoint */
     unsigned short size;
     unsigned short zero2;
     struct sk_buff *skb;
+    struct i596_rbd *v_next;
+    struct i596_rbd *b_addr;		/* This rbd addr from i596 view */
+    unsigned char *v_data;		/* Address from CPUs viewpoint */
 };
 
-#define TX_RING_SIZE 16
+#define TX_RING_SIZE 64
 #define RX_RING_SIZE 16
 
 struct i596_scb {
@@ -248,17 +312,14 @@
 	volatile struct i596_scp scp;
 	volatile struct i596_iscp iscp;
 	volatile struct i596_scb scb;
-	struct i596_cmd set_add;
-	char eth_addr[8];
-	struct i596_cmd set_conf;
-	char i596_config[16];
-	struct i596_cmd tdr;
-	struct i596_cmd mc_cmd;		/* Keep these three together!!! */
-	short mc_cnt;			/* Keep these three together!!! */
-	char mc_addrs[MAX_MC_CNT*6];	/* Keep these three together!!! */
+	struct sa_cmd sa_cmd;
+	struct cf_cmd cf_cmd;
+	struct tdr_cmd tdr_cmd;
+	struct mc_cmd mc_cmd;
 	unsigned long stat;
 	int last_restart __attribute__((aligned(4)));
-	struct i596_rfd *rx_tail;
+	struct i596_rfd *rfd_head;
+	struct i596_rbd *rbd_head;
 	struct i596_cmd *cmd_tail;
 	struct i596_cmd *cmd_head;
 	int cmd_backlog;
@@ -300,13 +361,13 @@
 static struct net_device_stats *i596_get_stats(struct net_device *dev);
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
 static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(char *);
+static void print_eth(unsigned char *buf, char *str);
 static void set_multicast_list(struct net_device *dev);
 
 static int rx_ring_size = RX_RING_SIZE;
 static int ticks_limit = 25;
-static int max_cmd_backlog = 16;
-
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
 
 static inline void CA(struct net_device *dev)
 {
@@ -317,7 +378,9 @@
 #endif
 #ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
-		volatile u32 i = *(volatile u32 *) (dev->base_addr);
+		volatile u32 i;
+
+		i = *(volatile u32 *) (dev->base_addr);
 	}
 #endif
 #ifdef ENABLE_APRICOT
@@ -349,29 +412,88 @@
 }
 
 
+static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+	while (--delcnt && lp->iscp.stat)
+		udelay(10);
+	if (!delcnt) {
+		printk("%s: %s, status %4.4x, cmd %4.4x.\n",
+		     dev->name, str, lp->scb.status, lp->scb.command);
+		return -1;
+	}
+	else
+		return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+	while (--delcnt && lp->scb.command)
+		udelay(10);
+	if (!delcnt) {
+		printk("%s: %s, status %4.4x, cmd %4.4x.\n",
+		     dev->name, str, lp->scb.status, lp->scb.command);
+		return -1;
+	}
+	else
+		return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_cmd *cmd;
+	struct i596_rfd *rfd;
+	struct i596_rbd *rbd;
+
+	printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+	       &lp->scp, lp->scp.sysbus, lp->scp.iscp);
+	printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+	       &lp->iscp, lp->iscp.stat, lp->iscp.scb);
+	printk("scb at %p, scb.status = %04x, .command = %04x,"
+		" .cmd = %p, .rfd = %p\n",
+	       &lp->scb, lp->scb.status, lp->scb.command,
+		lp->scb.cmd, lp->scb.rfd);
+	printk("   errors: crc %lx, align %lx, resource %lx,"
+               " over %lx, rcvdt %lx, short %lx\n",
+		lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
+		lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
+	cmd = lp->cmd_head;
+	while (cmd != I596_NULL) {
+		printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+		  cmd, cmd->status, cmd->command, cmd->b_next);
+		cmd = cmd->v_next;
+	}
+	rfd = lp->rfd_head;
+	printk("rfd_head = %p\n", rfd);
+	do {
+		printk ("   %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+                        " count %04x\n",
+			rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
+			rfd->count);
+		rfd = rfd->v_next;
+	} while (rfd != lp->rfd_head);
+	rbd = lp->rbd_head;
+	printk("rbd_head = %p\n", rbd);
+	do {
+		printk("   %p .count %04x, b_next %p, b_data %p, size %04x\n",
+			rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
+		rbd = rbd->v_next;
+	} while (rbd != lp->rbd_head);
+}
+
+
 #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
 static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
-	struct i596_cmd *cmd;
+	volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
 
-	struct i596_private *lp = (struct i596_private *) dev->priv;
-	printk("i596_error: lp = 0x%08x\n", (u32) lp);
-	printk("scp at %08x, .sysbus = %08x, .iscp = %08x\n",
-	       (u32) & lp->scp, (u32) lp->scp.sysbus, (u32) lp->scp.iscp);
-	printk("iscp at %08x, .stat = %08x, .scb = %08x\n",
-	       (u32) & lp->iscp, (u32) lp->iscp.stat, (u32) lp->iscp.scb);
-	printk("scb at %08x, .status = %04x, .command = %04x\n",
-	       (u32) & lp->scb, lp->scb.status, lp->scb.command);
-	printk("   .cmd = %08x, .rfd = %08x\n", (u32) lp->scb.cmd,
-	       (u32) lp->scb.rfd);
-	cmd = WSWAPcmd(lp->scb.cmd);
-	while (cmd && (u32) cmd < 0x1000000) {
-		printk("cmd at %08x, .status = %04x, .command = %04x, .next = %08x\n",
-		  (u32) cmd, cmd->status, cmd->command, (u32) cmd->next);
-		cmd = WSWAPcmd(cmd->next);
-	}
-	while (1);
+	pcc2[0x28] = 1;
+	pcc2[0x2b] = 0x1d;
+	printk("%s: Error interrupt\n", dev->name);
+	i596_display_data(dev);
 }
 #endif
 
@@ -382,9 +504,6 @@
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 
-	if (i596_debug > 1)
-		printk ("%s: init_rx_bufs %d.\n", dev->name, rx_ring_size);
-
 	/* First build the Receive Buffer Descriptor List */
 
 	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
@@ -393,28 +512,39 @@
 		if (skb == NULL)
 			panic("82596: alloc_skb() failed");
 		skb->dev = dev;
-		rbd->next = WSWAPrbd(rbd+1);
+		rbd->v_next = rbd+1;
+		rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
+		rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
 		rbd->skb = skb;
-		rbd->data = WSWAPchar(skb->tail);
+		rbd->v_data = skb->tail;
+		rbd->b_data = WSWAPchar(virt_to_bus(skb->tail));
 		rbd->size = PKT_BUF_SZ;
 #ifdef __mc68000__
 		cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ);
 #endif
 	}
-	lp->rbds[rx_ring_size-1].next = WSWAPrbd(lp->rbds);
+	lp->rbd_head = lp->rbds;
+	rbd = lp->rbds + rx_ring_size - 1;
+	rbd->v_next = lp->rbds;
+	rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds));
 
 	/* Now build the Receive Frame Descriptor List */
 
 	for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
-		rfd->rbd = (struct i596_rbd *)I596_NULL;
-		rfd->next = WSWAPrfd(rfd+1);
+		rfd->rbd = I596_NULL;
+		rfd->v_next = rfd+1;
+		rfd->v_prev = rfd-1;
+		rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1));
 		rfd->cmd = CMD_FLEX;
 	}
-	lp->scb.rfd = WSWAPrfd(lp->rfds);
-	lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
+	lp->rfd_head = lp->rfds;
+	lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+	rfd = lp->rfds;
+	rfd->rbd = lp->rbd_head;
+	rfd->v_prev = lp->rfds + rx_ring_size - 1;
 	rfd = lp->rfds + rx_ring_size - 1;
-	lp->rx_tail = rfd;
-	rfd->next = WSWAPrfd(lp->rfds);
+	rfd->v_next = lp->rfds;
+	rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
 	rfd->cmd = CMD_EOL|CMD_FLEX;
 }
 
@@ -431,15 +561,37 @@
 	}
 }
 
-static inline void init_i596_mem(struct net_device *dev)
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+	struct i596_private *lp = (struct i596_private *) dev->priv;
+	int i;
+
+	/* Ensure rx frame/buffer descriptors are tidy */
+
+	for (i = 0; i < rx_ring_size; i++) {
+		lp->rfds[i].rbd = I596_NULL;
+		lp->rfds[i].cmd = CMD_FLEX;
+	}
+	lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
+	lp->rfd_head = lp->rfds;
+	lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+	lp->rbd_head = lp->rbds;
+	lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
 	short ioaddr = dev->base_addr;
 #endif
-	int boguscnt = 100000;
 	unsigned long flags;
-	int i;
+
+	MPU_PORT(dev, PORT_RESET, 0);
+
+	udelay(100);		/* Wait 100us - seems to help */
 
 #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
 #ifdef ENABLE_MVME16x_NET
@@ -448,12 +600,12 @@
 
 		/* Disable all ints for now */
 		pcc2[0x28] = 1;
-		pcc2[0x2a] = 0x40;
+		pcc2[0x2a] = 0x48;
 		/* Following disables snooping.  Snooping is not required
 		 * as we make appropriate use of non-cached pages for
 		 * shared data, and cache_push/cache_clear.
 		 */
-		pcc2[0x2b] = 0x00;
+		pcc2[0x2b] = 0x08;
 	}
 #endif
 #ifdef ENABLE_BVME6000_NET
@@ -464,22 +616,22 @@
 	}
 #endif
 
-	MPU_PORT(dev, PORT_RESET, 0);
-
-	udelay(100);		/* Wait 100us - seems to help */
-
 	/* change the scp address */
 
-	MPU_PORT(dev, PORT_ALTSCP, &lp->scp);
+	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp));
 
 #elif defined(ENABLE_APRICOT)
 
-	/* change the scp address */
-	outw(0, ioaddr);
-	outw(0, ioaddr);
-	outb(4, ioaddr + 0xf);
-	outw(((((int) &lp->scp) & 0xffff) | 2), ioaddr);
-	outw((((int) &lp->scp) >> 16) & 0xffff, ioaddr);
+	{
+		u32 scp = virt_to_bus(&lp->scp);
+
+		/* change the scp address */
+		outw(0, ioaddr);
+		outw(0, ioaddr);
+		outb(4, ioaddr + 0xf);
+		outw(scp | 2, ioaddr);
+		outw(scp >> 16, ioaddr);
+	}
 #endif
 
 	lp->last_cmd = jiffies;
@@ -497,15 +649,14 @@
 		lp->scp.sysbus = 0x00440000;
 #endif
 
-	lp->scp.iscp = WSWAPiscp(&(lp->iscp));
-	lp->iscp.scb = WSWAPscb(&(lp->scb));
+	lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp)));
+	lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb)));
 	lp->iscp.stat = ISCP_BUSY;
 	lp->cmd_backlog = 0;
 
-	lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
+	lp->cmd_head = lp->scb.cmd = I596_NULL;
 
-	if (i596_debug > 1)
-		printk("%s: starting i82596.\n", dev->name);
+	DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));
 
 #if defined(ENABLE_APRICOT)
 	(void) inb(ioaddr + 0x10);
@@ -513,25 +664,12 @@
 #endif
 	CA(dev);
 
-	while (lp->iscp.stat)
-		if (--boguscnt == 0) {
-			printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n",
-			     dev->name, lp->scb.status, lp->scb.command);
-			break;
-		}
+	if (wait_istat(dev,lp,1000,"initialization timed out"))
+		goto failed;
+	DEB(DEB_INIT,printk("%s: i82596 initialization successful\n", dev->name));
 
 	/* Ensure rx frame/buffer descriptors are tidy */
-	/* Bit naff doing this here as well as in init_rx_bufs() */
-
-	for (i = 0; i < rx_ring_size; i++) {
-		lp->rfds[i].rbd = (struct i596_rbd *)I596_NULL;
-		lp->rfds[i].cmd = CMD_FLEX;
-	}
-	lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
-	lp->scb.rfd = WSWAPrfd(lp->rfds);
-	lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
-	lp->rx_tail = lp->rfds + rx_ring_size - 1;
-
+	rebuild_rx_bufs(dev);
 	lp->scb.command = 0;
 
 #ifdef ENABLE_MVME16x_NET
@@ -539,9 +677,8 @@
 		volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
 
 		/* Enable ints, etc. now */
-		pcc2[0x2a] = 0x08;
 		pcc2[0x2a] = 0x55;	/* Edge sensitive */
-		pcc2[0x2b] = 0x55;
+		pcc2[0x2b] = 0x15;
 	}
 #endif
 #ifdef ENABLE_BVME6000_NET
@@ -552,40 +689,40 @@
 	}
 #endif
 
-	memcpy(lp->i596_config, init_setup, 14);
-	lp->set_conf.command = CmdConfigure;
-	i596_add_cmd(dev, &lp->set_conf);
-
-	memcpy(lp->eth_addr, dev->dev_addr, 6);
-	lp->set_add.command = CmdSASetup;
-	i596_add_cmd(dev, &lp->set_add);
 
-	lp->tdr.command = CmdTDR;
-	i596_add_cmd(dev, &lp->tdr);
-
-	boguscnt = 200000;
+	DEB(DEB_INIT,printk("%s: queuing CmdConfigure\n", dev->name));
+	memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+	lp->cf_cmd.cmd.command = CmdConfigure;
+	i596_add_cmd(dev, &lp->cf_cmd.cmd);
+
+	DEB(DEB_INIT,printk("%s: queuing CmdSASetup\n", dev->name));
+	memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
+	lp->sa_cmd.cmd.command = CmdSASetup;
+	i596_add_cmd(dev, &lp->sa_cmd.cmd);
+
+	DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name));
+	lp->tdr_cmd.cmd.command = CmdTDR;
+	i596_add_cmd(dev, &lp->tdr_cmd.cmd);
 
 	spin_lock_irqsave (&lp->lock, flags);
 
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n",
-			     dev->name, lp->scb.status, lp->scb.command);
-			break;
-		}
+	if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START"))
+		goto failed;
+	DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name));
 	lp->scb.command = RX_START;
 	CA(dev);
 
 	spin_unlock_irqrestore (&lp->lock, flags);
 
-	boguscnt = 2000;
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n",
-			       lp->scb.status, lp->scb.command);
-			break;
-		}
-	return;
+	if (wait_cmd(dev,lp,1000,"RX_START not processed"))
+		goto failed;
+	DEB(DEB_INIT,printk("%s: Receive unit started OK\n", dev->name));
+	return 0;
+
+failed:
+	printk("%s: Failed to initialise 82596\n", dev->name);
+	MPU_PORT(dev, PORT_RESET, 0);
+	return -1;
 }
 
 static inline int i596_rx(struct net_device *dev)
@@ -595,23 +732,31 @@
 	struct i596_rbd *rbd;
 	int frames = 0;
 
-	if (i596_debug > 3)
-		printk ("i596_rx()\n");
+	DEB(DEB_RXFRAME,printk ("i596_rx(), rfd_head %p, rbd_head %p\n",
+			lp->rfd_head, lp->rbd_head));
 
-	rfd = WSWAPrfd(lp->scb.rfd);		/* Ref next frame to check */
+	rfd = lp->rfd_head;		/* Ref next frame to check */
 
-	while ((rfd->stat) & STAT_C) {		/* Loop while complete frames */
-		rbd = WSWAPrbd(rfd->rbd);       /* Ref associated buffer desc */
-
-		if (i596_debug >2)
-			print_eth(WSWAPchar(rbd->data));
-
-		if ((rfd->stat) & STAT_OK) {
+	while ((rfd->stat) & STAT_C) {	/* Loop while complete frames */
+		if (rfd->rbd == I596_NULL)
+			rbd = I596_NULL;
+		else if (rfd->rbd == lp->rbd_head->b_addr)
+			rbd = lp->rbd_head;
+		else {
+			printk("%s: rbd chain broken!\n", dev->name);
+			/* XXX Now what? */
+			rbd = I596_NULL;
+		}
+		DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+			rfd, rfd->rbd, rfd->stat));
+		
+		if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
 			/* a good frame */
 			int pkt_len = rbd->count & 0x3fff;
 			struct sk_buff *skb = rbd->skb;
 			int rx_in_place = 0;
 
+			DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
 			frames++;
 
 			/* Check if the packet is long enough to just accept
@@ -620,7 +765,6 @@
 
 			if (pkt_len > rx_copybreak) {
 				struct sk_buff *newskb;
-				char *temp;
 
 				/* Get fresh skbuff to replace filled one. */
 				newskb = dev_alloc_skb(PKT_BUF_SZ);
@@ -629,17 +773,12 @@
 					goto memory_squeeze;
 				}
 				/* Pass up the skb already on the Rx ring. */
-				temp = skb_put(skb, pkt_len);
-				if (WSWAPchar(rbd->data) != temp)
-					printk(KERN_ERR "%s: Internal consistency error "
-						"-- the skbuff addresses do not match"
-						" in i596_rx: %p vs. %p / %p.\n", dev->name,
-						WSWAPchar(rbd->data),
-						skb->head, temp);
+				skb_put(skb, pkt_len);
 				rx_in_place = 1;
 				rbd->skb = newskb;
 				newskb->dev = dev;
-				rbd->data = WSWAPchar(newskb->tail);
+				rbd->v_data = newskb->tail;
+				rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail));
 #ifdef __mc68000__
 				cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ);
 #endif
@@ -657,8 +796,7 @@
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
 					skb_reserve(skb, 2);
-					memcpy(skb_put(skb,pkt_len),
-						WSWAPchar(rbd->data), pkt_len);
+					memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
 				}
 				skb->protocol=eth_type_trans(skb,dev);
 				skb->len = pkt_len;
@@ -672,6 +810,8 @@
 			}
 		}
 		else {
+			DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n",
+					dev->name, rfd->stat));
 			lp->stats.rx_errors++;
 			if ((rfd->stat) & 0x0001)
 				lp->stats.collisions++;
@@ -691,52 +831,42 @@
 
 		/* Clear the buffer descriptor count and EOF + F flags */
 
-		if (rbd != (struct i596_rbd *)I596_NULL)
-			rbd->count=0;
-		else
-			printk("%s: Null rbd - oops!\n", dev->name);
+		if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+			rbd->count = 0;
+			lp->rbd_head = rbd->v_next;
+		}
 
 		/* Tidy the frame descriptor, marking it as end of list */
 
-		rfd->rbd = (struct i596_rbd *)I596_NULL;
+		rfd->rbd = I596_NULL;
 		rfd->stat = 0;
 		rfd->cmd = CMD_EOL|CMD_FLEX;
 		rfd->count = 0;
 
 		/* Remove end-of-list from old end descriptor */
 
-		lp->rx_tail->cmd = CMD_FLEX;
-
-		/* Update last frame descriptor to reference the one just
-		 * processed */
-
-		lp->rx_tail = rfd;
+		rfd->v_prev->cmd = CMD_FLEX;
 
 		/* Update record of next frame descriptor to process */
 
-		lp->scb.rfd = rfd->next;
-		rfd = WSWAPrfd(lp->scb.rfd);	/* Next frame desc. to check */
+		lp->scb.rfd = rfd->b_next;
+		lp->rfd_head = rfd->v_next;
+		rfd = lp->rfd_head;
 	}
 
-	if (i596_debug > 3)
-		printk ("frames %d\n", frames);
+	DEB(DEB_RXFRAME,printk ("frames %d\n", frames));
 
 	return 0;
 }
 
 
-static inline void i596_cleanup_cmd(struct i596_private *lp)
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
 {
 	struct i596_cmd *ptr;
-	int boguscnt = 1000;
 
-	if (i596_debug > 4)
-		printk("i596_cleanup_cmd\n");
-
-	while (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
+	while (lp->cmd_head != I596_NULL) {
 		ptr = lp->cmd_head;
-
-		lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+		lp->cmd_head = ptr->v_next;
 		lp->cmd_backlog--;
 
 		switch ((ptr->command) & 0x7) {
@@ -750,45 +880,28 @@
 				lp->stats.tx_errors++;
 				lp->stats.tx_aborted_errors++;
 
-				ptr->next = (struct i596_cmd *) I596_NULL;
+				ptr->v_next = ptr->b_next = I596_NULL;
 				tx_cmd->cmd.command = 0;  /* Mark as free */
 				break;
 			}
-		case CmdMulticastList:
-			{
-				ptr->next = (struct i596_cmd *) I596_NULL;
-				break;
-			}
 		default:
-			ptr->next = (struct i596_cmd *) I596_NULL;
+			ptr->v_next = ptr->b_next = I596_NULL;
 		}
 	}
 
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n",
-			       lp->scb.status, lp->scb.command);
-			break;
-		}
-	lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+	wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
+	lp->scb.cmd = I596_NULL;
 }
 
 static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
 {
-	int boguscnt = 1000;
 	unsigned long flags;
 
-	if (i596_debug > 1)
-		printk("i596_reset\n");
+	DEB(DEB_RESET,printk("i596_reset\n"));
 
 	spin_lock_irqsave (&lp->lock, flags);
 
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n",
-			       lp->scb.status, lp->scb.command);
-			break;
-		}
+	wait_cmd(dev,lp,100,"i596_reset timed out");
 
 	netif_stop_queue(dev);
 
@@ -796,17 +909,10 @@
 	CA(dev);
 
 	/* wait for shutdown */
-	boguscnt = 4000;
-
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n",
-			       lp->scb.status, lp->scb.command);
-			break;
-		}
+	wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
 	spin_unlock_irqrestore (&lp->lock, flags);
 
-	i596_cleanup_cmd(lp);
+	i596_cleanup_cmd(dev,lp);
 	i596_rx(dev);
 
 	netif_start_queue(dev);
@@ -818,46 +924,28 @@
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
-	int boguscnt = 1000;
 
-	if (i596_debug > 4)
-		printk("i596_add_cmd\n");
+	DEB(DEB_ADDCMD,printk("i596_add_cmd\n"));
 
 	cmd->status = 0;
 	cmd->command |= (CMD_EOL | CMD_INTR);
-	cmd->next = (struct i596_cmd *) I596_NULL;
+	cmd->v_next = cmd->b_next = I596_NULL;
 
 	spin_lock_irqsave (&lp->lock, flags);
 
-	/*
-	 * RGH  300597:  Looks to me like there could be a race condition
-	 * here.  Just because we havn't picked up all the command items
-	 * yet, doesn't mean that the 82596 hasn't finished processing
-	 * them.  So, we may need to do a CUC_START anyway.
-	 * Maybe not.  If it interrupts saying the CU is idle when there
-	 * is still something in the cmd queue, the int handler with restart
-	 * the CU.
-	 */
-
-	if (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
-		lp->cmd_tail->next = WSWAPcmd(cmd);
+	if (lp->cmd_head != I596_NULL) {
+		lp->cmd_tail->v_next = cmd;
+		lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status));
 	} else {
 		lp->cmd_head = cmd;
-		while (lp->scb.command)
-			if (--boguscnt == 0) {
-				printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n",
-				       lp->scb.status, lp->scb.command);
-				break;
-			}
-		lp->scb.cmd = WSWAPcmd(cmd);
+		wait_cmd(dev,lp,100,"i596_add_cmd timed out");
+		lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status));
 		lp->scb.command = CUC_START;
 		CA(dev);
 	}
 	lp->cmd_tail = cmd;
 	lp->cmd_backlog++;
 
-	lp->cmd_head = WSWAPcmd(lp->scb.cmd);	/* Is this redundant?  RGH 300597 */
-
 	spin_unlock_irqrestore (&lp->lock, flags);
 
 	if (lp->cmd_backlog > max_cmd_backlog) {
@@ -874,11 +962,14 @@
 
 static int i596_open(struct net_device *dev)
 {
-	if (i596_debug > 1)
-		printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
+	int res = 0;
+
+	DEB(DEB_OPEN,printk("%s: i596_open() irq %d.\n", dev->name, dev->irq));
 
-	if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev))
+	if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
+		printk("%s: IRQ %d not free\n", dev->name, dev->irq);
 		return -EAGAIN;
+	}
 #ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		if (request_irq(0x56, &i596_error, 0, "i82596_error", dev))
@@ -892,9 +983,12 @@
 	MOD_INC_USE_COUNT;
 
 	/* Initialize the 82596 memory */
-	init_i596_mem(dev);
+	if (init_i596_mem(dev)) {
+		res = -EAGAIN;
+		free_irq(dev->irq, dev);
+	}
 
-	return 0;		/* Always succeed */
+	return res;
 }
 
 static void i596_tx_timeout (struct net_device *dev)
@@ -903,21 +997,19 @@
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
-	printk ("%s: transmit timed out, status resetting.\n", dev->name);
+	DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
+			dev->name));
 
 	lp->stats.tx_errors++;
 
 	/* Try to restart the adaptor */
 	if (lp->last_restart == lp->stats.tx_packets) {
-		if (i596_debug > 1)
-			printk ("Resetting board.\n");
-
+		DEB(DEB_ERRORS,printk ("Resetting board.\n"));
 		/* Shutdown and restart */
 		i596_reset (dev, lp, ioaddr);
 	} else {
 		/* Issue a channel attention signal */
-		if (i596_debug > 1)
-			printk ("Kicking board.\n");
+		DEB(DEB_ERRORS,printk ("Kicking board.\n"));
 		lp->scb.command = CUC_START | RX_START;
 		CA (dev);
 		lp->last_restart = lp->stats.tx_packets;
@@ -933,55 +1025,47 @@
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	dev->trans_start = jiffies;
 
-	if (i596_debug > 2)
-		printk("%s: 82596 start xmit\n", dev->name);
-
-	if (i596_debug > 3)
-		printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
-				skb->len, (unsigned int)skb->data);
+	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
+				skb->len, (unsigned int)skb->data));
 
 	netif_stop_queue(dev);
-	
-	{
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		dev->trans_start = jiffies;
 
-		tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
-		tbd = lp->tbds + lp->next_tx_cmd;
+	tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+	tbd = lp->tbds + lp->next_tx_cmd;
+
+	if (tx_cmd->cmd.command) {
+		DEB(DEB_ERRORS,printk ("%s: xmit ring full, dropping packet.\n",
+				dev->name));
+		lp->stats.tx_dropped++;
 
-		if (tx_cmd->cmd.command) {
-			printk ("%s: xmit ring full, dropping packet.\n",
-					dev->name);
-			lp->stats.tx_dropped++;
-
-			dev_kfree_skb(skb);
-		} else {
-			if (++lp->next_tx_cmd == TX_RING_SIZE)
-				lp->next_tx_cmd = 0;
-			tx_cmd->tbd = WSWAPtbd(tbd);
-			tbd->next = (struct i596_tbd *) I596_NULL;
-
-			tx_cmd->cmd.command = CMD_FLEX | CmdTx;
-			tx_cmd->skb = skb;
-
-			tx_cmd->pad = 0;
-			tx_cmd->size = 0;
-			tbd->pad = 0;
-			tbd->size = EOF | length;
+		dev_kfree_skb(skb);
+	} else {
+		if (++lp->next_tx_cmd == TX_RING_SIZE)
+			lp->next_tx_cmd = 0;
+		tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));
+		tbd->next = I596_NULL;
+
+		tx_cmd->cmd.command = CMD_FLEX | CmdTx;
+		tx_cmd->skb = skb;
+
+		tx_cmd->pad = 0;
+		tx_cmd->size = 0;
+		tbd->pad = 0;
+		tbd->size = EOF | length;
 
-			tbd->data = WSWAPchar(skb->data);
+		tbd->data = WSWAPchar(virt_to_bus(skb->data));
 
 #ifdef __mc68000__
-			cache_push(virt_to_phys(skb->data), length);
+		cache_push(virt_to_phys(skb->data), length);
 #endif
-			if (i596_debug > 3)
-				print_eth(skb->data);
-			i596_add_cmd(dev, (struct i596_cmd *) tx_cmd);
+		DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
+		i596_add_cmd(dev, &tx_cmd->cmd);
 
-			lp->stats.tx_packets++;
-			lp->stats.tx_bytes += length;
-		}
+		lp->stats.tx_packets++;
+		lp->stats.tx_bytes += length;
 	}
 
 	netif_start_queue(dev);
@@ -989,21 +1073,17 @@
 	return 0;
 }
 
-static void print_eth(char *add)
+static void print_eth(unsigned char *add, char *str)
 {
 	int i;
 
-	printk("print_eth(%08x)\n", (unsigned int) add);
-	printk("Dest  ");
+	printk("i596 0x%p, ", add);
 	for (i = 0; i < 6; i++)
-		printk(" %2.2X", (unsigned char) add[i]);
-	printk("\n");
-
-	printk("Source");
+		printk(" %02X", add[i + 6]);
+	printk(" -->");
 	for (i = 0; i < 6; i++)
-		printk(" %2.2X", (unsigned char) add[i + 6]);
-	printk("\n");
-	printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
+		printk(" %02X", add[i]);
+	printk(" %02X%02X, %s\n", add[12], add[13], str);
 }
 
 int __init i82596_probe(struct net_device *dev)
@@ -1011,19 +1091,17 @@
 	int i;
 	struct i596_private *lp;
 	char eth_addr[6];
+	static int probed = 0;
 
+	if (probed)
+		return -ENODEV;
+	probed++;
 #ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
-		static int probed = 0;
-#ifdef XXX_FIXME
 		if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
 			printk("Ethernet probe disabled - chip not present\n");
-			return ENODEV;
+			return -ENODEV;
 		}
-#endif
-		if (probed)
-			return ENODEV;
-		probed++;
 		memcpy(eth_addr, (void *) 0xfffc1f2c, 6);	/* YUCK! Get addr from NOVRAM */
 		dev->base_addr = MVME_I596_BASE;
 		dev->irq = (unsigned) MVME16x_IRQ_I596;
@@ -1044,48 +1122,59 @@
 	}
 #endif
 #ifdef ENABLE_APRICOT
-	int checksum = 0;
-	int ioaddr = 0x300;
+	{
+		int checksum = 0;
+		int ioaddr = 0x300;
 
-	/* this is easy the ethernet interface can only be at 0x300 */
-	/* first check nothing is already registered here */
+		/* this is easy the ethernet interface can only be at 0x300 */
+		/* first check nothing is already registered here */
 
-	if (check_region(ioaddr, I596_TOTAL_SIZE))
-		return ENODEV;
+		if (check_region(ioaddr, I596_TOTAL_SIZE)) {
+			printk("82596: IO address 0x%04x in use\n", ioaddr);
+			return -ENODEV;
+		}
 
-	for (i = 0; i < 8; i++) {
-		eth_addr[i] = inb(ioaddr + 8 + i);
-		checksum += eth_addr[i];
-	}
+		for (i = 0; i < 8; i++) {
+			eth_addr[i] = inb(ioaddr + 8 + i);
+			checksum += eth_addr[i];
+		}
 
-	/* checksum is a multiple of 0x100, got this wrong first time
-	   some machines have 0x100, some 0x200. The DOS driver doesn't
-	   even bother with the checksum */
+		/* checksum is a multiple of 0x100, got this wrong first time
+		   some machines have 0x100, some 0x200. The DOS driver doesn't
+		   even bother with the checksum */
 
-	if (checksum % 0x100)
-		return ENODEV;
+		if (checksum % 0x100)
+			return -ENODEV;
 
-	/* Some other boards trip the checksum.. but then appear as ether
-	   address 0. Trap these - AC */
+		/* Some other boards trip the checksum.. but then appear as
+		 * ether address 0. Trap these - AC */
 
-	if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
-		return ENODEV;
+		if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
+			return -ENODEV;
 
-	request_region(ioaddr, I596_TOTAL_SIZE, "i596");
+		request_region(ioaddr, I596_TOTAL_SIZE, "i596");
 
-	dev->base_addr = ioaddr;
-	dev->irq = 10;
+		dev->base_addr = ioaddr;
+		dev->irq = 10;
+	}
+#endif
+	dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
+	if (!dev->mem_start) {
+#ifdef ENABLE_APRICOT
+		release_region(dev->base_addr, I596_TOTAL_SIZE);
 #endif
+		return -ENOMEM;
+	}
+
 	ether_setup(dev);
-	printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr);
+	DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr));
 
 	for (i = 0; i < 6; i++)
-		printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+		DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
 
-	printk(" IRQ %d.\n", dev->irq);
+	DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
 
-	if (i596_debug > 0)
-		printk(version);
+	DEB(DEB_PROBE,printk(version));
 
 	/* The 82596-specific entries in the device structure. */
 	dev->open = i596_open;
@@ -1095,16 +1184,13 @@
 	dev->set_multicast_list = set_multicast_list;
 	dev->tx_timeout = i596_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	
 
-	dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
 	dev->priv = (void *)(dev->mem_start);
 
 	lp = (struct i596_private *) dev->priv;
-	if (i596_debug)
-		printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
+	DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
 			dev->name, (unsigned long)lp,
-			sizeof(struct i596_private), (unsigned long)&lp->scb);
+			sizeof(struct i596_private), (unsigned long)&lp->scb));
 	memset((void *) lp, 0, sizeof(struct i596_private));
 
 #ifdef __mc68000__
@@ -1113,8 +1199,8 @@
 	kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
 #endif
 	lp->scb.command = 0;
-	lp->scb.cmd = (struct i596_cmd *) I596_NULL;
-	lp->scb.rfd = (struct i596_rfd *) I596_NULL;
+	lp->scb.cmd = I596_NULL;
+	lp->scb.rfd = I596_NULL;
 	lp->lock = SPIN_LOCK_UNLOCKED;
 
 	return 0;
@@ -1125,7 +1211,6 @@
 	struct net_device *dev = dev_id;
 	struct i596_private *lp;
 	short ioaddr;
-	int boguscnt = 2000;
 	unsigned short status, ack_cmd = 0;
 
 #ifdef ENABLE_BVME6000_NET
@@ -1140,145 +1225,116 @@
 		printk("i596_interrupt(): irq %d for unknown device.\n", irq);
 		return;
 	}
-	if (i596_debug > 3)
-		printk("%s: i596_interrupt(): irq %d\n", dev->name, irq);
 
 	ioaddr = dev->base_addr;
 	lp = (struct i596_private *) dev->priv;
-	
+
 	spin_lock (&lp->lock);
 
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
-			break;
-		}
+	wait_cmd(dev,lp,100,"i596 interrupt, timeout");
 	status = lp->scb.status;
 
-	if (i596_debug > 4)
-		printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status);
+	DEB(DEB_INTS,printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+			dev->name, irq, status));
 
 	ack_cmd = status & 0xf000;
 
 	if ((status & 0x8000) || (status & 0x2000)) {
 		struct i596_cmd *ptr;
 
-		if ((i596_debug > 4) && (status & 0x8000))
-			printk("%s: i596 interrupt completed command.\n", dev->name);
-		if ((i596_debug > 4) && (status & 0x2000))
-			printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
+		if ((status & 0x8000))
+			DEB(DEB_INTS,printk("%s: i596 interrupt completed command.\n", dev->name));
+		if ((status & 0x2000))
+			DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
 
-		while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C)) {
+		while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {
 			ptr = lp->cmd_head;
 
-			if (i596_debug > 2)
-				printk("cmd_head->status = %04x, ->command = %04x\n",
-				       lp->cmd_head->status, lp->cmd_head->command);
-			lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+			DEB(DEB_STATUS,printk("cmd_head->status = %04x, ->command = %04x\n",
+				       lp->cmd_head->status, lp->cmd_head->command));
+			lp->cmd_head = ptr->v_next;
 			lp->cmd_backlog--;
 
 			switch ((ptr->command) & 0x7) {
 			case CmdTx:
-				{
-					struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
-					struct sk_buff *skb = tx_cmd->skb;
-
-					if ((ptr->status) & STAT_OK) {
-						if (i596_debug > 2)
-							print_eth(skb->data);
-					} else {
-						lp->stats.tx_errors++;
-						if ((ptr->status) & 0x0020)
-							lp->stats.collisions++;
-						if (!((ptr->status) & 0x0040))
-							lp->stats.tx_heartbeat_errors++;
-						if ((ptr->status) & 0x0400)
-							lp->stats.tx_carrier_errors++;
-						if ((ptr->status) & 0x0800)
-							lp->stats.collisions++;
-						if ((ptr->status) & 0x1000)
-							lp->stats.tx_aborted_errors++;
-					}
-
-					dev_kfree_skb(skb);
-
-					ptr->next = (struct i596_cmd *) I596_NULL;
-					tx_cmd->cmd.command = 0; /* Mark free */
-					break;
-				}
-			case CmdMulticastList:
-				{
-					ptr->next = (struct i596_cmd *) I596_NULL;
-					break;
+			    {
+				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+				struct sk_buff *skb = tx_cmd->skb;
+
+				if ((ptr->status) & STAT_OK) {
+					DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
+				} else {
+					lp->stats.tx_errors++;
+					if ((ptr->status) & 0x0020)
+						lp->stats.collisions++;
+					if (!((ptr->status) & 0x0040))
+						lp->stats.tx_heartbeat_errors++;
+					if ((ptr->status) & 0x0400)
+						lp->stats.tx_carrier_errors++;
+					if ((ptr->status) & 0x0800)
+						lp->stats.collisions++;
+					if ((ptr->status) & 0x1000)
+						lp->stats.tx_aborted_errors++;
 				}
+
+				dev_kfree_skb_irq(skb);
+
+				tx_cmd->cmd.command = 0; /* Mark free */
+				break;
+			    }
 			case CmdTDR:
-				{
-					unsigned long status = *((unsigned long *) (ptr + 1));
+			    {
+				unsigned short status = ((struct tdr_cmd *)ptr)->status;
 
-					if (status & 0x8000) {
-						if (i596_debug > 3)
-							printk("%s: link ok.\n", dev->name);
-					} else {
-						if (status & 0x4000)
-							printk("%s: Transceiver problem.\n", dev->name);
-						if (status & 0x2000)
-							printk("%s: Termination problem.\n", dev->name);
-						if (status & 0x1000)
-							printk("%s: Short circuit.\n", dev->name);
-
-						if (i596_debug > 1)
-							printk("%s: Time %ld.\n", dev->name, status & 0x07ff);
-					}
-					break;
+				if (status & 0x8000) {
+					DEB(DEB_ANY,printk("%s: link ok.\n", dev->name));
+				} else {
+					if (status & 0x4000)
+						printk("%s: Transceiver problem.\n", dev->name);
+					if (status & 0x2000)
+						printk("%s: Termination problem.\n", dev->name);
+					if (status & 0x1000)
+						printk("%s: Short circuit.\n", dev->name);
+
+					DEB(DEB_TDR,printk("%s: Time %d.\n", dev->name, status & 0x07ff));
 				}
+				break;
+			    }
 			case CmdConfigure:
-				{
-					ptr->next = (struct i596_cmd *) I596_NULL;
-					/* Zap command so set_multicast_list() knows it is free */
-					ptr->command = 0;
-					break;
-				}
-			default:
-				ptr->next = (struct i596_cmd *) I596_NULL;
+				/* Zap command so set_multicast_list() knows it is free */
+				ptr->command = 0;
+				break;
 			}
+			ptr->v_next = ptr->b_next = I596_NULL;
 			lp->last_cmd = jiffies;
 		}
 
 		ptr = lp->cmd_head;
-		while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail)) {
+		while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
 			ptr->command &= 0x1fff;
-			ptr = WSWAPcmd(ptr->next);
+			ptr = ptr->v_next;
 		}
 
-		if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) &&
-		    netif_running(dev))
+		if ((lp->cmd_head != I596_NULL))
 			ack_cmd |= CUC_START;
-		lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+		lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));
 	}
 	if ((status & 0x1000) || (status & 0x4000)) {
-		if ((i596_debug > 4) && (status & 0x4000))
-			printk("%s: i596 interrupt received a frame.\n", dev->name);
+		if ((status & 0x4000))
+			DEB(DEB_INTS,printk("%s: i596 interrupt received a frame.\n", dev->name));
+		i596_rx(dev);
 		/* Only RX_START if stopped - RGH 07-07-96 */
 		if (status & 0x1000) {
-			if (netif_running(dev))
+			if (netif_running(dev)) {
+				DEB(DEB_ERRORS,printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
 				ack_cmd |= RX_START;
-			if (i596_debug > 1)
-				printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0);
+				lp->stats.rx_errors++;
+				lp->stats.rx_fifo_errors++;
+				rebuild_rx_bufs(dev);
+			}
 		}
-		i596_rx(dev);
 	}
-	/* acknowledge the interrupt */
-
-/*      COMMENTED OUT <<<<<
-   if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start))
-   ack_cmd |= CUC_START;
- */
-	boguscnt = 1000;
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
-			break;
-		}
+	wait_cmd(dev,lp,100,"i596 interrupt, timeout");
 	lp->scb.command = ack_cmd;
 
 #ifdef ENABLE_MVME16x_NET
@@ -1304,49 +1360,33 @@
 #endif
 	CA(dev);
 
-	if (i596_debug > 4)
-		printk("%s: exiting interrupt.\n", dev->name);
+	DEB(DEB_INTS,printk("%s: exiting interrupt.\n", dev->name));
 
 	spin_unlock (&lp->lock);
-	
 	return;
 }
 
 static int i596_close(struct net_device *dev)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	int boguscnt = 2000;
 	unsigned long flags;
 
 	netif_stop_queue(dev);
 
-	if (i596_debug > 1)
-		printk("%s: Shutting down ethercard, status was %4.4x.\n",
-		       dev->name, lp->scb.status);
+	DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n",
+		       dev->name, lp->scb.status));
 
 	save_flags(flags);
 	cli();
 
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("%s: close1 timed out with status %4.4x, cmd %4.4x.\n",
-			     dev->name, lp->scb.status, lp->scb.command);
-			break;
-		}
+	wait_cmd(dev,lp,100,"close1 timed out");
 	lp->scb.command = CUC_ABORT | RX_ABORT;
 	CA(dev);
 
-	boguscnt = 2000;
-
-	while (lp->scb.command)
-		if (--boguscnt == 0) {
-			printk("%s: close2 timed out with status %4.4x, cmd %4.4x.\n",
-			     dev->name, lp->scb.status, lp->scb.command);
-			break;
-		}
+	wait_cmd(dev,lp,100,"close2 timed out");
 	restore_flags(flags);
-
-	i596_cleanup_cmd(lp);
+	DEB(DEB_STRUCT,i596_display_data(dev));
+	i596_cleanup_cmd(dev,lp);
 
 #ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
@@ -1388,35 +1428,33 @@
 static void set_multicast_list(struct net_device *dev)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	struct i596_cmd *cmd;
 	int config = 0, cnt;
 
-	if (i596_debug > 1)
-		printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF");
+	DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
 
-	if ((dev->flags & IFF_PROMISC) && !(lp->i596_config[8] & 0x01)) {
-		lp->i596_config[8] |= 0x01;
+	if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
+		lp->cf_cmd.i596_config[8] |= 0x01;
 		config = 1;
 	}
-	if (!(dev->flags & IFF_PROMISC) && (lp->i596_config[8] & 0x01)) {
-		lp->i596_config[8] &= ~0x01;
+	if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
+		lp->cf_cmd.i596_config[8] &= ~0x01;
 		config = 1;
 	}
-	if ((dev->flags & IFF_ALLMULTI) && (lp->i596_config[11] & 0x20)) {
-		lp->i596_config[11] &= ~0x20;
+	if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
+		lp->cf_cmd.i596_config[11] &= ~0x20;
 		config = 1;
 	}
-	if (!(dev->flags & IFF_ALLMULTI) && !(lp->i596_config[11] & 0x20)) {
-		lp->i596_config[11] |= 0x20;
+	if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
+		lp->cf_cmd.i596_config[11] |= 0x20;
 		config = 1;
 	}
 	if (config) {
-		if (lp->set_conf.command)
+		if (lp->cf_cmd.cmd.command)
 			printk("%s: config change request already queued\n",
 			       dev->name);
 		else {
-			lp->set_conf.command = CmdConfigure;
-			i596_add_cmd(dev, &lp->set_conf);
+			lp->cf_cmd.cmd.command = CmdConfigure;
+			i596_add_cmd(dev, &lp->cf_cmd.cmd);
 		}
 	}
 
@@ -1431,20 +1469,19 @@
 	if (dev->mc_count > 0) {
 		struct dev_mc_list *dmi;
 		unsigned char *cp;
+		struct mc_cmd *cmd;
 
 		cmd = &lp->mc_cmd;
-		cmd->command = CmdMulticastList;
-		*((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
-		cp = ((unsigned char *) (cmd + 1)) + 2;
-		for(dmi=dev->mc_list;cnt && dmi!=NULL;dmi=dmi->next,cnt--) {
+		cmd->cmd.command = CmdMulticastList;
+		cmd->mc_cnt = dev->mc_count * 6;
+		cp = cmd->mc_addrs;
+		for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
 			memcpy(cp, dmi->dmi_addr, 6);
 			if (i596_debug > 1)
-				printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, *(cp + 0), *(cp + 1), *(cp + 2), *(cp + 3), *(cp + 4), *(cp + 5));
-			cp += 6;
+				DEB(DEB_MULTI,printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
+						dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
 		}
-		if (i596_debug > 2)
-			print_eth(((char *) (cmd + 1)) + 2);
-		i596_add_cmd(dev, cmd);
+		i596_add_cmd(dev, &cmd->cmd);
 	}
 }
 
@@ -1495,7 +1532,7 @@
 	 * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
 	 */
 
-	kernel_set_cachemode((u32)(dev_82596.mem_start), 4096,
+	kernel_set_cachemode((void *)(dev_82596.mem_start), 4096,
 			IOMAP_FULL_CACHING);
 #endif
 	free_page ((u32)(dev_82596.mem_start));
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.3.99-pre5/linux/drivers/net/8390.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/8390.c	Wed Apr 12 09:38:53 2000
@@ -181,7 +181,7 @@
  * ei_close - shut down network device
  * @dev: network device to close
  *
- * Opposite of ei_open. Only used when "ifconfig <devname> down" is done.
+ * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
  */
 int ei_close(struct net_device *dev)
 {
@@ -416,7 +416,7 @@
  * the 8390 via the card specific functions and fire them at the networking
  * stack. We also handle transmit completions and wake the transmit path if
  * neccessary. We also update the counters and do other housekeeping as
- * needed
+ * needed.
  */
 
 void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
@@ -530,7 +530,7 @@
  * is a much better solution as it avoids kernel based Tx timeouts, and
  * an unnecessary card reset.
  *
- * Called with lock held
+ * Called with lock held.
  */
 
 static void ei_tx_err(struct net_device *dev)
@@ -573,7 +573,7 @@
  * @dev: network device for which tx intr is handled
  *
  * We have finished a transmit: check for errors and then trigger the next
- * packet to be sent. Called with lock held
+ * packet to be sent. Called with lock held.
  */
 
 static void ei_tx_intr(struct net_device *dev)
@@ -665,7 +665,7 @@
  * @dev: network device with which receive will be run
  *
  * We have a good packet(s), get it/them out of the buffers. 
- * Called with lock held
+ * Called with lock held.
  */
 
 static void ei_receive(struct net_device *dev)
@@ -801,7 +801,7 @@
  * This includes causing "the NIC to defer indefinitely when it is stopped
  * on a busy network."  Ugh.
  * Called with lock held. Don't call this with the interrupts off or your
- * computer will hate you - it takes 10mS or so. 
+ * computer will hate you - it takes 10ms or so. 
  */
 
 static void ei_rx_overrun(struct net_device *dev)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.99-pre5/linux/drivers/net/Space.c	Wed Apr 12 10:02:34 2000
+++ linux/drivers/net/Space.c	Thu Apr 13 17:06:00 2000
@@ -683,6 +683,46 @@
 #define	NEXT_DEV	(&sbni0_dev)
 #endif 
 	
+/* S/390 channels */
+#ifdef CONFIG_CTC
+    extern int ctc_probe(struct net_device *dev);
+    static struct net_device ctc7_dev =
+       {"ctc7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV,  ctc_probe};
+    static struct net_device ctc6_dev =
+       {"ctc6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc7_dev, ctc_probe};
+    static struct net_device ctc5_dev =
+       {"ctc5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc6_dev, ctc_probe};
+    static struct net_device ctc4_dev =
+       {"ctc4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc5_dev, ctc_probe};
+    static struct net_device ctc3_dev =
+       {"ctc3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc4_dev, ctc_probe};
+    static struct net_device ctc2_dev =
+       {"ctc2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc3_dev, ctc_probe};
+    static struct net_device ctc1_dev =
+       {"ctc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc2_dev, ctc_probe};
+    static struct net_device ctc0_dev =
+       {"ctc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc1_dev, ctc_probe}; 
+
+    static struct net_device escon7_dev =
+       {"escon7", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc0_dev,   ctc_probe};
+    static struct net_device escon6_dev =
+       {"escon6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon7_dev, ctc_probe};
+    static struct net_device escon5_dev =
+       {"escon5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon6_dev, ctc_probe};
+    static struct net_device escon4_dev =
+       {"escon4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon5_dev, ctc_probe};
+    static struct net_device escon3_dev =
+       {"escon3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon4_dev, ctc_probe};
+    static struct net_device escon2_dev =
+       {"escon2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon3_dev, ctc_probe};
+    static struct net_device escon1_dev =
+       {"escon1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon2_dev, ctc_probe};
+    static struct net_device escon0_dev =
+       {"escon0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon1_dev, ctc_probe}; 
+
+#undef  NEXT_DEV
+#define NEXT_DEV        (&escon0_dev)                                  
+#endif  
 	
 	
 /*
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.3.99-pre5/linux/drivers/net/acenic.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/net/acenic.c	Fri Apr 21 16:08:52 2000
@@ -2949,6 +2949,6 @@
 
 /*
  * Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o acenic.o acenic.c"
+ * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o acenic.o acenic.c"
  * End:
  */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c
--- v2.3.99-pre5/linux/drivers/net/am79c961a.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/am79c961a.c	Tue Apr 25 17:38:33 2000
@@ -33,40 +33,49 @@
 
 #include "am79c961a.h"
 
+static int am79c961_probe1 (struct net_device *dev);
+static int am79c961_open (struct net_device *dev);
+static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev);
+static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static void am79c961_rx (struct net_device *dev, struct dev_priv *priv);
+static void am79c961_tx (struct net_device *dev, struct dev_priv *priv);
+static int am79c961_close (struct net_device *dev);
+static struct enet_statistics *am79c961_getstats (struct net_device *dev);
+static void am79c961_setmulticastlist (struct net_device *dev);
+static void am79c961_timeout(struct net_device *dev);
+
 static unsigned int net_debug = NET_DEBUG;
 
 static void
 am79c961_setmulticastlist (struct net_device *dev);
 
-static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n";
+static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.01\n";
 
 #define FUNC_PROLOGUE \
 	struct dev_priv *priv = (struct dev_priv *)dev->priv
 
 /* --------------------------------------------------------------------------- */
 
+#ifdef __arm__
 static void
 write_rreg (unsigned long base, unsigned int reg, unsigned short val)
 {
-	__asm__("
-		strh	%1, [%2]	@ NET_RAP
-		strh	%0, [%2, #-4]	@ NET_RDP
+	__asm__("str%?h	%1, [%2]	@ NET_RAP
+		str%?h	%0, [%2, #-4]	@ NET_RDP
 		" : : "r" (val), "r" (reg), "r" (0xf0000464));
 }
 
 static inline void
 write_ireg (unsigned long base, unsigned int reg, unsigned short val)
 {
-	__asm__("
-		strh	%1, [%2]	@ NET_RAP
-		strh	%0, [%2, #8]	@ NET_RDP
+	__asm__("str%?h	%1, [%2]	@ NET_RAP
+		str%?h	%0, [%2, #8]	@ NET_RDP
 		" : : "r" (val), "r" (reg), "r" (0xf0000464));
 }
 
 #define am_writeword(dev,off,val)\
-	__asm__("\
-		strh	%0, [%1]\
-		" : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+	__asm__("str%?h	%0, [%1]" : : \
+		"r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
 
 static inline void
 am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
@@ -74,30 +83,28 @@
 	offset = 0xe0000000 + (offset << 1);
 	length = (length + 1) & ~1;
 	if ((int)buf & 2) {
-		__asm__ __volatile__("
-			strh	%2, [%0], #4
-		" : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+		__asm__ __volatile__("str%?h	%2, [%0], #4"
+		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
 		buf += 2;
 		length -= 2;
 	}
 	while (length > 8) {
 		unsigned int tmp, tmp2;
 		__asm__ __volatile__("
-			ldmia	%1!, {%2, %3}
-			strh	%2, [%0], #4
-			mov	%2, %2, lsr #16
-			strh	%2, [%0], #4
-			strh	%3, [%0], #4
-			mov	%3, %3, lsr #16
-			strh	%3, [%0], #4
+			ldm%?ia	%1!, {%2, %3}
+			str%?h	%2, [%0], #4
+			mov%?	%2, %2, lsr #16
+			str%?h	%2, [%0], #4
+			str%?h	%3, [%0], #4
+			mov%?	%3, %3, lsr #16
+			str%?h	%3, [%0], #4
 		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
 		  : "0" (offset), "1" (buf));
 		length -= 8;
 	}
 	while (length > 0) {
-		__asm__ __volatile__("
-			strh	%2, [%0], #4
-		" : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+		__asm__ __volatile__("str%?h	%2, [%0], #4"
+		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
 		buf += 2;
 		length -= 2;
 	}
@@ -107,9 +114,8 @@
 read_rreg (unsigned int base_addr, unsigned int reg)
 {
 	unsigned short v;
-	__asm__("
-		strh	%1, [%2]	@ NET_RAP
-		ldrh	%0, [%2, #-4]	@ NET_IDP
+	__asm__("str%?h	%1, [%2]	@ NET_RAP
+		ldr%?h	%0, [%2, #-4]	@ NET_IDP
 		" : "=r" (v): "r" (reg), "r" (0xf0000464));
 	return v;
 }
@@ -120,9 +126,7 @@
 	unsigned long address = 0xe0000000 + (off << 1);
 	unsigned short val;
 
-	__asm__("
-		ldrh	%0, [%1]
-		" : "=r" (val): "r" (address));
+	__asm__("ldr%?h	%0, [%1]" : "=r" (val): "r" (address));
 	return val;
 }
 
@@ -134,23 +138,23 @@
 	if ((int)buf & 2) {
 		unsigned int tmp;
 		__asm__ __volatile__("
-			ldrh	%2, [%0], #4
-			strb	%2, [%1], #1
-			mov	%2, %2, lsr #8
-			strb	%2, [%1], #1
+			ldr%?h	%2, [%0], #4
+			str%?b	%2, [%1], #1
+			mov%?	%2, %2, lsr #8
+			str%?b	%2, [%1], #1
 		" : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
 		length -= 2;
 	}
 	while (length > 8) {
 		unsigned int tmp, tmp2, tmp3;
 		__asm__ __volatile__("
-			ldrh	%2, [%0], #4
-			ldrh	%3, [%0], #4
-			orr	%2, %2, %3, lsl #16
-			ldrh	%3, [%0], #4
-			ldrh	%4, [%0], #4
-			orr	%3, %3, %4, lsl #16
-			stmia	%1!, {%2, %3}
+			ldr%?h	%2, [%0], #4
+			ldr%?h	%3, [%0], #4
+			orr%?	%2, %2, %3, lsl #16
+			ldr%?h	%3, [%0], #4
+			ldr%?h	%4, [%0], #4
+			orr%?	%3, %3, %4, lsl #16
+			stm%?ia	%1!, {%2, %3}
 		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
 		  : "0" (offset), "1" (buf));
 		length -= 8;
@@ -158,14 +162,17 @@
 	while (length > 0) {
 		unsigned int tmp;
 		__asm__ __volatile__("
-			ldrh	%2, [%0], #4
-			strb	%2, [%1], #1
-			mov	%2, %2, lsr #8
-			strb	%2, [%1], #1
+			ldr%?h	%2, [%0], #4
+			str%?b	%2, [%1], #1
+			mov%?	%2, %2, lsr #8
+			str%?b	%2, [%1], #1
 		" : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
 		length -= 2;
 	}
 }
+#else
+#error Not compatable
+#endif
 
 static int
 am79c961_ramtest(struct net_device *dev, unsigned int val)
@@ -259,7 +266,7 @@
 	write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
 	write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
-	write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM);
+	write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
 	write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
 }
 
@@ -304,7 +311,7 @@
 	/*
 	 * The PNP initialisation should have been done by the ether bootp loader.
 	 */
-	inb ((dev->base_addr + NET_RESET) >> 1);	/* reset the device */
+	inb((dev->base_addr + NET_RESET) >> 1);	/* reset the device */
 
 	udelay (5);
 
@@ -343,6 +350,7 @@
 	dev->hard_start_xmit = am79c961_sendpacket;
 	dev->get_stats = am79c961_getstats;
 	dev->set_multicast_list = am79c961_setmulticastlist;
+	dev->tx_timeout = am79c961_timeout;
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
@@ -382,14 +390,15 @@
 
 	memset (&priv->stats, 0, sizeof (priv->stats));
 
-	if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev))
+	if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) {
+		MOD_DEC_USE_COUNT;
 		return -EAGAIN;
+	}
 
 	am79c961_init_for_open(dev);
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+	netif_start_queue(dev);
+
 	return 0;
 }
 
@@ -399,8 +408,7 @@
 static int
 am79c961_close(struct net_device *dev)
 {
-	dev->tbusy = 1;
-	dev->start = 0;
+	netif_stop_queue(dev);
 
 	am79c961_init(dev);
 
@@ -420,26 +428,116 @@
 	return &priv->stats;
 }
 
+static inline u32 update_crc(u32 crc, u8 byte)
+{
+	int i;
+
+	for (i = 8; i != 0; i--) {
+		byte ^= crc & 1;
+		crc >>= 1;
+
+		if (byte & 1)
+			crc ^= 0xedb88320;
+
+		byte >>= 1;
+	}
+
+	return crc;
+}
+
+static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
+{
+	if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
+		int i, idx, bit;
+		u32 crc;
+
+		crc = 0xffffffff;
+
+		for (i = 0; i < ETH_ALEN; i++)
+			crc = update_crc(crc, dmi->dmi_addr[i]);
+
+		idx = crc >> 30;
+		bit = (crc >> 26) & 15;
+
+		hash[idx] |= 1 << bit;
+	}
+}
+
 /*
  * Set or clear promiscuous/multicast mode filter for this adaptor.
- *
- * We don't attempt any packet filtering.  The card may have a SEEQ 8004
- * in which does not have the other ethernet address registers present...
  */
 static void am79c961_setmulticastlist (struct net_device *dev)
 {
 	unsigned long flags;
-	int i;
+	unsigned short multi_hash[4], mode;
+	int i, stopped;
 
-	dev->flags &= ~IFF_ALLMULTI;
+	mode = MODE_PORT0;
 
-	i = MODE_PORT0;
-	if (dev->flags & IFF_PROMISC)
-		i |= MODE_PROMISC;
+	if (dev->flags & IFF_PROMISC) {
+		mode |= MODE_PROMISC;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		memset(multi_hash, 0xff, sizeof(multi_hash));
+	} else {
+		struct dev_mc_list *dmi;
 
-	save_flags_cli (flags);
-	write_rreg (dev->base_addr, MODE, i);
-	restore_flags (flags);
+		memset(multi_hash, 0x00, sizeof(multi_hash));
+
+		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+			am79c961_mc_hash(dmi, multi_hash);
+	}
+
+	save_flags_cli(flags);
+
+	stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
+
+	if (!stopped) {
+		/*
+		 * Put the chip into suspend mode
+		 */
+		write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
+
+		/*
+		 * Spin waiting for chip to report suspend mode
+		 */
+		while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
+			restore_flags(flags);
+			nop();
+			save_flags_cli(flags);
+		}
+	}
+
+	/*
+	 * Update the multicast hash table
+	 */
+	for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
+		write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
+
+	/*
+	 * Write the mode register
+	 */
+	write_rreg(dev->base_addr, MODE, mode);
+
+	if (!stopped) {
+		/*
+		 * Put the chip back into running mode
+		 */
+		write_rreg(dev->base_addr, CTRL1, 0);
+	}
+
+	restore_flags(flags);
+}
+
+static void am79c961_timeout(struct net_device *dev)
+{
+	printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
+		dev->name);
+
+	/*
+	 * ought to do some setup of the tx side here
+	 */
+
+	netif_wake_queue(dev);
 }
 
 /*
@@ -449,46 +547,34 @@
 am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned int hdraddr, bufaddr;
+	unsigned int head;
+	unsigned long flags;
 
-	if (!dev->tbusy) {
-again:
-		if (!test_and_set_bit(0, (void*)&dev->tbusy)) {
-			unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-			unsigned int hdraddr, bufaddr;
-			unsigned long flags;
-
-			hdraddr = priv->txhdr + (priv->txhead << 3);
-			bufaddr = priv->txbuffer[priv->txhead];
-			priv->txhead ++;
-			if (priv->txhead >= TX_BUFFERS)
-				priv->txhead = 0;
-
-			am_writebuffer (dev, bufaddr, skb->data, length);
-			am_writeword (dev, hdraddr + 4, -length);
-			am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
-
-			save_flags_cli (flags);
-			write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
-			dev->trans_start = jiffies;
-			restore_flags (flags);
-
-			if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
-				dev->tbusy = 0;
-			dev_kfree_skb (skb);
-			return 0;
-		} else
-			printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
-			return 1;
-	} else {
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
-			return 1;
-		printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name);
-		/* Try to restart the adaptor. */
-		dev->tbusy = 0;
-		dev->trans_start = jiffies;
-		goto again;
-	}
+	head = priv->txhead;
+	hdraddr = priv->txhdr + (head << 3);
+	bufaddr = priv->txbuffer[head];
+	head += 1;
+	if (head >= TX_BUFFERS)
+		head = 0;
+
+	am_writebuffer (dev, bufaddr, skb->data, length);
+	am_writeword (dev, hdraddr + 4, -length);
+	am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
+	priv->txhead = head;
+
+	save_flags_cli (flags);
+	write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
+	dev->trans_start = jiffies;
+	restore_flags (flags);
+
+	if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
+		netif_stop_queue(dev);
+
+	dev_kfree_skb(skb);
+
+	return 0;
 }
 
 static void
@@ -503,8 +589,6 @@
 		printk(KERN_DEBUG "am79c961irq: %d ", irq);
 #endif
 
-	dev->interrupt = 1;
-
 	status = read_rreg (dev->base_addr, CSR0);
 	write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
 
@@ -515,8 +599,6 @@
 	if (status & CSR0_MISS)
 		priv->stats.rx_dropped ++;
 
-	dev->interrupt = 0;
-
 #if NET_DEBUG > 1
 	if(net_debug & DEBUG_INT)
 		printk("done\n");
@@ -613,7 +695,7 @@
 			am_writeword (dev, hdraddr + 6, 0);
 
 			if (status2 & TST_RTRY)
-				priv->stats.collisions += 1;
+				priv->stats.collisions += 16;
 			if (status2 & TST_LCOL)
 				priv->stats.tx_window_errors ++;
 			if (status2 & TST_LCAR)
@@ -625,7 +707,5 @@
 		priv->stats.tx_packets ++;
 	} while (priv->txtail != priv->txhead);
 
-	dev->tbusy = 0;
-	mark_bh (NET_BH);
+	netif_wake_queue(dev);
 }
-
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/am79c961a.h linux/drivers/net/am79c961a.h
--- v2.3.99-pre5/linux/drivers/net/am79c961a.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/am79c961a.h	Tue Apr 25 17:38:33 2000
@@ -45,6 +45,7 @@
 #define CSR3_EMBA	0x0008
 #define CSR3_DXMT2PD	0x0010
 #define CSR3_LAPPEN	0x0020
+#define CSR3_DXSUFLO	0x0040
 #define CSR3_IDONM	0x0100
 #define CSR3_TINTM	0x0200
 #define CSR3_RINTM	0x0400
@@ -53,6 +54,9 @@
 #define CSR3_BABLM	0x4000
 #define CSR3_MASKALL	0x5F00
 
+#define CTRL1		5
+#define CTRL1_SPND	0x0001
+
 #define LADRL		8
 #define LADRM1		9
 #define LADRM2		10
@@ -97,8 +101,8 @@
 #define TMD_ERR		0x4000
 #define TMD_OWN		0x8000
 
-#define TST_RTRY	0x0200
-#define TST_LCAR	0x0400
+#define TST_RTRY	0x0400
+#define TST_LCAR	0x0800
 #define TST_LCOL	0x1000
 #define TST_UFLO	0x4000
 
@@ -115,14 +119,5 @@
 };
 
 extern int	am79c961_probe (struct net_device *dev);
-static int	am79c961_probe1 (struct net_device *dev);
-static int	am79c961_open (struct net_device *dev);
-static int	am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void	am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static void	am79c961_rx (struct net_device *dev, struct dev_priv *priv);
-static void	am79c961_tx (struct net_device *dev, struct dev_priv *priv);
-static int	am79c961_close (struct net_device *dev);
-static struct enet_statistics *am79c961_getstats (struct net_device *dev);
-static void	am79c961_setmulticastlist (struct net_device *dev);
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/appletalk/ltpc.c linux/drivers/net/appletalk/ltpc.c
--- v2.3.99-pre5/linux/drivers/net/appletalk/ltpc.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/net/appletalk/ltpc.c	Wed Apr 12 09:38:53 2000
@@ -1253,17 +1253,15 @@
 			/* usage message */
 			printk (KERN_ERR
 				"ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+			return 0;
 		}
-		return 1;
 	} else {
 		io = ints[1];
 		if (ints[0] > 1) {
 			irq = ints[2];
-			return 1;
 		}
 		if (ints[0] > 2) {
 			dma = ints[3];
-			return 1;
 		}
 		/* ignore any other paramters */
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c
--- v2.3.99-pre5/linux/drivers/net/arcnet/arcnet.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/arcnet/arcnet.c	Wed Apr 12 09:38:53 2000
@@ -107,7 +107,7 @@
 
 void __init arcnet_init(void)
 {
-	static int arcnet_inited __initdata = 0;
+	static int arcnet_inited = 0;
 	int count;
 
 	if (arcnet_inited++)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/arcnet/com90io.c linux/drivers/net/arcnet/com90io.c
--- v2.3.99-pre5/linux/drivers/net/arcnet/com90io.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/arcnet/com90io.c	Wed Apr 12 09:38:53 2000
@@ -426,7 +426,7 @@
 
 	s = get_options(s, 4, ints);
 	if (!ints[0])
-		return 1;
+		return 0;
 	dev = alloc_bootmem(sizeof(struct net_device) + 10);
 	memset(dev, 0, sizeof(struct net_device) + 10);
 	dev->name = (char *) (dev + 1);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.3.99-pre5/linux/drivers/net/cs89x0.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/net/cs89x0.c	Fri Apr 14 09:37:10 2000
@@ -48,10 +48,23 @@
                     : Don't call netif_wake_queue() in net_send_packet()
                     : Fixed an out-of-mem bug in dma_rx()
                     : Updated Documentation/cs89x0.txt
+
+  Andrew Morton     : andrewm@uow.edu.au / Kernel 2.3.99-pre1
+                    : Use skb_reserve to longword align IP header (two places)
+                    : Remove a delay loop from dma_rx()
+                    : Replace '100' with HZ
+                    : Clean up a couple of skb API abuses
+                    : Added 'cs89x0_dma=N' kernel boot option
+                    : Correctly initialise lp->lock in non-module compile
+
+  Andrew Morton     : andrewm@uow.edu.au / Kernel 2.3.99-pre4-1
+                    : MOD_INC/DEC race fix (see
+                    : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html)
+
 */
 
 static char *version =
-"cs89x0.c: (kernel 2.3.48) Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
+"cs89x0.c: v2.3.99-pre1-2 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
 
 /* ======================= end of configuration ======================= */
 
@@ -121,7 +134,7 @@
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
 
 #if DEBUGGING
-static unsigned int net_debug = 5;
+static unsigned int net_debug = DEBUGGING;
 #else
 #define net_debug 0	/* gcc will remove all the debug code for us */
 #endif
@@ -190,6 +203,21 @@
 /* Example routines you must write ;->. */
 #define tx_done(dev) 1
 
+/*
+ * Permit 'cs89x0_dma=N' in the kernel boot environment
+ */
+#if !defined(MODULE) && (ALLOW_DMA != 0)
+static int g_cs89x0_dma;
+
+static int __init dma_fn(char *str)
+{
+	g_cs89x0_dma = simple_strtol(str,NULL,0);
+	return 1;
+}
+
+__setup("cs89x0_dma=", dma_fn);
+#endif	/* !defined(MODULE) && (ALLOW_DMA != 0) */
+
 
 /* Check for a network adaptor of this type, and return '0' iff one exists.
    If dev->base_addr == 0, probe all likely locations.
@@ -318,7 +346,17 @@
 			retval = ENOMEM;
 			goto out;
 		}
-                memset(dev->priv, 0, sizeof(struct net_local));
+		lp = (struct net_local *)dev->priv;
+		memset(lp, 0, sizeof(*lp));
+		spin_lock_init(&lp->lock);
+#if !defined(MODULE) && (ALLOW_DMA != 0)
+		if (g_cs89x0_dma)
+		{
+			lp->use_dma = 1;
+			lp->dma = g_cs89x0_dma;
+			lp->dmasize = 16;	/* Could make this an option... */
+		}
+#endif
         }
 	lp = (struct net_local *)dev->priv;
 
@@ -612,12 +650,6 @@
 	int status, length;
 	unsigned char *bp = lp->rx_dma_ptr;
 
-	{
-		int i;
-		for (i = 0; i < 1000; i++)
-			;
-	}
-
 	status = bp[0] + (bp[1]<<8);
 	length = bp[2] + (bp[3]<<8);
 	bp += 4;
@@ -632,7 +664,7 @@
 	}
 
 	/* Malloc up new buffer. */
-	skb = alloc_skb(length, GFP_ATOMIC);
+	skb = dev_alloc_skb(length + 2);
 	if (skb == NULL) {
 		if (net_debug)	/* I don't think we want to do this to a stressed system */
 			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
@@ -645,8 +677,7 @@
 		lp->rx_dma_ptr = bp;
 		return;
 	}
-
-	skb->len = length;
+	skb_reserve(skb, 2);	/* longword align L3 header */
 	skb->dev = dev;
 
 	if (bp + length > lp->end_dma_buff) {
@@ -720,7 +751,7 @@
 	writereg(dev, PP_SelfCTL, selfcontrol);
 
 	/* Wait for the DC/DC converter to power up - 500ms */
-	while (jiffies - timenow < 100)
+	while (jiffies - timenow < HZ)
 		;
 
 }
@@ -914,6 +945,9 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int result = 0;
 	int i;
+	int ret;
+
+	MOD_INC_USE_COUNT;
 
 	if (dev->irq < 2) {
 		/* Allow interrupts to be generated by the chip */
@@ -938,13 +972,15 @@
 			writereg(dev, PP_BusCTL, 0);	/* disable interrupts. */
 			if (net_debug)
 				printk("cs89x0: can't get an interrupt\n");
-			return -EAGAIN;
+			ret = -EAGAIN;
+			goto bad_out;
 		}
 	} else {
 		if (((1 << dev->irq) & lp->irq_map) == 0) {
 			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
-			return -EAGAIN;
+			ret = -EAGAIN;
+			goto bad_out;
 		}
 /* FIXME: Cirrus' release had this: */
 		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
@@ -956,7 +992,8 @@
 		if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) {
 			if (net_debug)
 				printk("cs89x0: request_irq(%d) failed\n", dev->irq);
-			return -EAGAIN;
+			ret = -EAGAIN;
+			goto bad_out;
 		}
 	}
 
@@ -1032,7 +1069,8 @@
 #endif
                 writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
                 free_irq(dev->irq, dev);
-		return -EAGAIN;
+		ret = -EAGAIN;
+		goto bad_out;
 	}
 
         /* set the hardware to the configured choice */
@@ -1125,11 +1163,13 @@
 		 | dma_busctl(dev)
 #endif
                  );
-        MOD_INC_USE_COUNT;
         netif_start_queue(dev);
 	if (net_debug)
 		printk("cs89x0: net_open() succeeded\n");
 	return 0;
+bad_out:
+	MOD_DEC_USE_COUNT;
+	return ret;
 }
 
 static void net_timeout(struct net_device *dev)
@@ -1317,7 +1357,7 @@
 	}
 
 	/* Malloc up new buffer. */
-	skb = alloc_skb(length, GFP_ATOMIC);
+	skb = dev_alloc_skb(length + 2);
 	if (skb == NULL) {
 #if 0		/* Again, this seems a cruel thing to do */
 		printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
@@ -1325,10 +1365,10 @@
 		lp->stats.rx_dropped++;
 		return;
 	}
-	skb->len = length;
+	skb_reserve(skb, 2);	/* longword align L3 header */
 	skb->dev = dev;
 
-	insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1);
+	insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1);
 	if (length & 1)
 		skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.3.99-pre5/linux/drivers/net/de4x5.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/de4x5.c	Fri Apr 21 16:08:52 2000
@@ -5923,9 +5923,7 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
  *
- * Delete -D__SMP__ below if you didn't define this in your kernel
  * Delete -DMODVERSIONS below if you didn't define this in your kernel
  *
  *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c"
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.3.99-pre5/linux/drivers/net/eepro.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/eepro.c	Wed Apr 12 09:38:53 2000
@@ -1614,6 +1614,8 @@
 
 		if (register_netdev(d) == 0)
 			n_eepro++;
+		else
+			break;
 	}
 	
 	return n_eepro ? 0 : -ENODEV;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.99-pre5/linux/drivers/net/eepro100.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/eepro100.c	Fri Apr 21 16:08:45 2000
@@ -1285,7 +1285,7 @@
 		del_timer(&sp->timer);
 		end_bh_atomic();
 #else /* LINUX_VERSION_CODE */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		del_timer_sync(&sp->timer);
 #else /* SMP */
 		del_timer(&sp->timer);
@@ -2258,7 +2258,6 @@
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c
--- v2.3.99-pre5/linux/drivers/net/hamradio/baycom_epp.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/hamradio/baycom_epp.c	Wed Apr 12 09:38:53 2000
@@ -1509,7 +1509,7 @@
 
 static int __init baycom_epp_setup(char *str)
 {
-        static unsigned __initdata nr_dev = 0;
+        static unsigned __initlocaldata nr_dev = 0;
 	int ints[2];
 
         if (nr_dev >= NR_PORTS)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.3.99-pre5/linux/drivers/net/hp100.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/hp100.c	Wed Apr 12 09:38:57 2000
@@ -1800,9 +1800,9 @@
 	     donecount);
 #endif
 #ifdef LINUX_2_1
-      dev_kfree_skb( lp->txrhead->skb );
+      dev_kfree_skb_any( lp->txrhead->skb );
 #else
-      dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );
+      dev_kfree_skb_any( lp->txrhead->skb, FREE_WRITE );
 #endif
       lp->txrhead->skb=(void *)NULL;
       lp->txrhead=lp->txrhead->next;
@@ -1960,9 +1960,9 @@
   hp100_ints_on();
 	
 #ifdef LINUX_2_1
-  dev_kfree_skb( skb );
+  dev_kfree_skb_any( skb );
 #else
-  dev_kfree_skb( skb, FREE_WRITE );
+  dev_kfree_skb_any( skb, FREE_WRITE );
 #endif
 	
 #ifdef HP100_DEBUG_TX
@@ -2198,9 +2198,9 @@
 #endif
 	  if(ptr->skb!=NULL)
 #ifdef LINUX_2_1
-	    dev_kfree_skb( ptr->skb );
+	    dev_kfree_skb_any( ptr->skb );
 #else
-	    dev_kfree_skb( ptr->skb, FREE_READ );					
+	    dev_kfree_skb_any( ptr->skb, FREE_READ );					
 #endif
           lp->stats.rx_errors++;
         }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.3.99-pre5/linux/drivers/net/ne2k-pci.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/ne2k-pci.c	Fri Apr 21 16:27:21 2000
@@ -188,9 +188,10 @@
 		return -ENODEV;
 	}
 	
-	if (pci_enable_device (pdev)) {
+	i = pci_enable_device (pdev);
+	if (i) {
 		printk (KERN_ERR "ne2k-pci: cannot enable device\n");
-		return -EIO;
+		return i;
 	}
 	
 	if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
@@ -292,6 +293,7 @@
 	/* Set up the rest of the parameters. */
 	dev->irq = irq;
 	dev->base_addr = ioaddr;
+	pdev->driver_data = dev;
 
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (ethdev_init(dev)) {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/3c575_cb.c linux/drivers/net/pcmcia/3c575_cb.c
--- v2.3.99-pre5/linux/drivers/net/pcmcia/3c575_cb.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/pcmcia/3c575_cb.c	Wed Dec 31 16:00:00 1969
@@ -1,2159 +0,0 @@
-/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
-/*
-	Written 1996-1999 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU Public License, incorporated herein by reference.
-
-	This driver is for the 3Com "Vortex" and "Boomerang" series ethercards.
-	Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597
-	and the EtherLink XL 3c900 and 3c905 cards.
-
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
-	Linux Kernel Additions:
-	
-	LK1.1.2 (March 19, 2000)
-	* New PCI interface (jgarzik)
-
-*/
-
-static char *version =
-"3c575_cb.c:v0.99L+LK1.1.2  3/19/2000  Donald Becker and others  http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
-
-/* "Knobs" that adjust features and parameters. */
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1512 effectively disables this feature. */
-static const int rx_copybreak = 200;
-/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const int mtu = 1500;
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 32;
-
-/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
-#define vortex_debug debug
-#ifdef VORTEX_DEBUG
-static int vortex_debug = VORTEX_DEBUG;
-#else
-static int vortex_debug = 1;
-#endif
-
-/* Some values here only for performance evaluation and path-coverage
-   debugging. */
-static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
-
-/* A few values that may be tweaked. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((400*HZ)/1000)
-
-/* Keep the ring sizes a power of two for efficiency. */
-#define TX_RING_SIZE	16
-#define RX_RING_SIZE	32
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
-
-#ifndef __OPTIMIZE__
-#warning  You must compile this file with the correct options!
-#warning  See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <asm/irq.h>			/* For NR_IRQS only. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
-   This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
-
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-
-/* Operational parameter that usually are not changed. */
-
-/* The Vortex size is twice that of the original EtherLinkIII series: the
-   runtime register window, window 1, is now always mapped in.
-   The Boomerang size is twice as large as the Vortex -- it has additional
-   bus master control registers. */
-#define VORTEX_TOTAL_SIZE 0x20
-#define BOOMERANG_TOTAL_SIZE 0x40
-
-/* Set iff a MII transceiver on any interface requires mdio preamble.
-   This only set with the original DP83840 on older 3c905 boards, so the extra
-   code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required = 0;
-
-#define PFX "3c575_cb: "
-
-
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the 3Com FastEtherLink and FastEtherLink
-XL, 3Com's PCI to 10/100baseT adapters.  It also works with the 10Mbs
-versions of the FastEtherLink cards.  The supported product IDs are
-  3c590, 3c592, 3c595, 3c597, 3c900, 3c905
-
-The related ISA 3c515 is supported with a separate driver, 3c515.c, included
-with the kernel source or available from
-    cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-
-The EEPROM settings for media type and forced-full-duplex are observed.
-The EEPROM media type should be left at the default "autoselect" unless using
-10base2 or AUI connections which cannot be reliably detected.
-
-III. Driver operation
-
-The 3c59x series use an interface that's very similar to the previous 3c5x9
-series.  The primary interface is two programmed-I/O FIFOs, with an
-alternate single-contiguous-region bus-master transfer (see next).
-
-The 3c900 "Boomerang" series uses a full-bus-master interface with separate
-lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
-DEC Tulip and Intel Speedo3.  The first chip version retains a compatible
-programmed-I/O interface that has been removed in 'B' and subsequent board
-revisions.
-
-One extension that is advertised in a very large font is that the adapters
-are capable of being bus masters.  On the Vortex chip this capability was
-only for a single contiguous region making it far less useful than the full
-bus master capability.  There is a significant performance impact of taking
-an extra interrupt or polling for the completion of each transfer, as well
-as difficulty sharing the single transfer engine between the transmit and
-receive threads.  Using DMA transfers is a win only with large blocks or
-with the flawed versions of the Intel Orion motherboard PCI controller.
-
-The Boomerang chip's full-bus-master interface is useful, and has the
-currently-unused advantages over other similar chips that queued transmit
-packets may be reordered and receive buffer groups are associated with a
-single frame.
-
-With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
-Rather than a fixed intermediate receive buffer, this scheme allocates
-full-sized skbuffs as receive buffers.  The value RX_COPYBREAK is used as
-the copying breakpoint: it is chosen to trade-off the memory wasted by
-passing the full-sized skbuff to the queue layer for all frames vs. the
-copying cost of copying a frame to a correctly-sized skbuff.
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-IV. Notes
-
-Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development
-3c590, 3c595, and 3c900 boards.
-The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
-the EISA version is called "Demon".  According to Terry these names come
-from rides at the local amusement park.
-
-The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes!
-This driver only supports ethernet packets because of the skbuff allocation
-limit of 4K.
-*/
-
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   of the drivers, and will likely be provided by some future kernel.
-*/
-enum pci_flags_bit {
-	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
-
-enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
-	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-
-
-enum vortex_chips {
-	CH_3C590 = 0,
-	CH_3C595_1,
-	CH_3C595_2,
-	CH_3C595_3,
-	CH_VORTEX,
-	CH_3C900_1,
-	CH_3C900_2,
-	CH_3C900_3,
-	CH_3C900B_FL,
-	CH_3C905_1,
-	CH_3C905_2,
-	CH_3C905B_1,
-	CH_3C905B_2,
-	CH_3C905B_FX,
-	CH_3C905C,
-	CH_3C980,
-	CH_3CSOHO100_TX,
-	CH_3C555,
-	CH_3C575_1,
-	CH_3CCFE575,
-	CH_3CCFE575CT,
-	CH_3CCFE656,
-	CH_3CCFEM656,
-	CH_3C575_2,
-	CH_BOOMERANG,
-};
-
-
-/* note: this array directly indexed by above enums, and MUST
- * be kept in sync with both the enums above, and the PCI device
- * table below
- */
-static struct vortex_chip_info {
-	const char *name;
-	int flags;
-	int drv_flags;
-	int io_size;
-} vortex_info_tbl[] = {
-	{"3c590 Vortex 10Mbps",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c595 Vortex 100baseTx",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c595 Vortex 100baseT4",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c595 Vortex 100base-MII",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3Com Vortex",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
-	{"3c900 Boomerang 10baseT",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
-	{"3c900 Boomerang 10Mbps Combo",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
-	{"3c900 Cyclone 10Mbps Combo",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
-	{"3c900B-FL Cyclone 10base-FL",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
-	{"3c905 Boomerang 100baseTx",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
-	{"3c905 Boomerang 100baseT4",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
-	{"3c905B Cyclone 100baseTx",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
-	{"3c905B Cyclone 10/100/BNC",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
-	{"3c905B-FX Cyclone 100baseFx",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
-	{"3c905C Tornado",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
-	{"3c980 Cyclone",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
-	{"3cSOHO100-TX Hurricane",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
-	{"3c555 Laptop Hurricane",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
-	{"3c575 Boomerang CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
-	{"3CCFE575 Cyclone CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
-	{"3CCFE575CT Cyclone CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
-	{"3CCFE656 Cyclone CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
-	{"3CCFEM656 Cyclone CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
-	{"3c575 series CardBus (unknown version)",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
-	{"3Com Boomerang (unknown version)",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
-	{0,}, /* 0 terminated list. */
-};
-
-
-static struct pci_device_id vortex_pci_tbl[] __devinit = {
-	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
-	{ 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 },
-	{ 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 },
-	{ 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 },
-	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX },
-	{ 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 },
-	{ 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 },
-	{ 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
-	{ 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL },
-	{ 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 },
-	{ 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 },
-	{ 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 },
-	{ 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
-	{ 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
-	{ 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
-	{ 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
-	{ 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
-	{ 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
-	{ 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
-	{ 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
-	{ 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
-	{ 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
-	{ 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
-	{ 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_2 },
-	{ 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_BOOMERANG },
-	{0,},						/* 0 terminated list. */
-};
-MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
-
-
-/* Operational definitions.
-   These are not used by other compilation units and thus are not
-   exported in a ".h" file.
-
-   First the windows.  There are eight register windows, with the command
-   and status registers available in each.
-   */
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-/* The top five bits written to EL3_CMD are a command, the lower
-   11 bits are the parameter, if applicable.
-   Note that 11 parameters bits was fine for ethernet, but the new chip
-   can handle FDDI length frames (~4500 octets) and now parameters count
-   32-bit 'Dwords' rather than octets. */
-
-enum vortex_cmd {
-	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
-	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
-	UpStall = 6<<11, UpUnstall = (6<<11)+1,
-	DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
-	RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
-	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
-	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
-	SetTxThreshold = 18<<11, SetTxStart = 19<<11,
-	StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
-	StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
-	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
-
-/* Bits in the general status register. */
-enum vortex_status {
-	IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004,
-	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
-	IntReq = 0x0040, StatsFull = 0x0080,
-	DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
-	DMAInProgress = 1<<11,			/* DMA controller is still busy.*/
-	CmdInProgress = 1<<12,			/* EL3_CMD is still busy.*/
-};
-
-/* Register window 1 offsets, the window used in normal operation.
-   On the Vortex this window is always mapped at offsets 0x10-0x1f. */
-enum Window1 {
-	TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
-	RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
-	TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
-};
-enum Window0 {
-	Wn0EepromCmd = 10,		/* Window 0: EEPROM command register. */
-	Wn0EepromData = 12,		/* Window 0: EEPROM results register. */
-	IntrStatus=0x0E,		/* Valid in all windows. */
-};
-enum Win0_EEPROM_bits {
-	EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
-	EEPROM_EWENB = 0x30,		/* Enable erasing/writing for 10 msec. */
-	EEPROM_EWDIS = 0x00,		/* Disable EWENB before 10 msec timeout. */
-};
-/* EEPROM locations. */
-enum eeprom_offset {
-	PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
-	EtherLink3ID=7, IFXcvrIO=8, IRQLine=9,
-	NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
-	DriverTune=13, Checksum=15};
-
-enum Window2 {			/* Window 2. */
-	Wn2_ResetOptions=12,
-};
-enum Window3 {			/* Window 3: MAC/config bits. */
-	Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
-};
-union wn3_config {
-	int i;
-	struct w3_config_fields {
-		unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
-		int pad8:8;
-		unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
-		int pad24:7;
-	} u;
-};
-
-enum Window4 {		/* Window 4: Xcvr/media bits. */
-	Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
-};
-enum Win4_Media_bits {
-	Media_SQE = 0x0008,		/* Enable SQE error counting for AUI. */
-	Media_10TP = 0x00C0,	/* Enable link beat and jabber for 10baseT. */
-	Media_Lnk = 0x0080,		/* Enable just link beat for 100TX/100FX. */
-	Media_LnkBeat = 0x0800,
-};
-enum Window7 {					/* Window 7: Bus Master control. */
-	Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
-};
-/* Boomerang bus master control registers. */
-enum MasterCtrl {
-	PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
-	TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,
-};
-
-/* The Rx and Tx descriptor lists.
-   Caution Alpha hackers: these types are 32 bits!  Note also the 8 byte
-   alignment contraint on tx_ring[] and rx_ring[]. */
-#define LAST_FRAG  0x80000000			/* Last Addr/Len pair in descriptor. */
-struct boom_rx_desc {
-	u32 next;					/* Last entry points to 0.   */
-	s32 status;
-	u32 addr;					/* Up to 63 addr/len pairs possible. */
-	s32 length;					/* Set LAST_FRAG to indicate last pair. */
-};
-/* Values for the Rx status entry. */
-enum rx_desc_status {
-	RxDComplete=0x00008000, RxDError=0x4000,
-	/* See boomerang_rx() for actual error bits */
-	IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
-	IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
-};
-
-struct boom_tx_desc {
-	u32 next;					/* Last entry points to 0.   */
-	s32 status;					/* bits 0:12 length, others see below.  */
-	u32 addr;
-	s32 length;
-};
-
-/* Values for the Tx status entry. */
-enum tx_desc_status {
-	CRCDisable=0x2000, TxDComplete=0x8000,
-	AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
-	TxIntrUploaded=0x80000000,		/* IRQ when in FIFO, but maybe not sent. */
-};
-
-/* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
-
-struct vortex_private {
-	/* The Rx and Tx rings should be quad-word-aligned. */
-	struct boom_rx_desc rx_ring[RX_RING_SIZE];
-	struct boom_tx_desc tx_ring[TX_RING_SIZE];
-	/* The addresses of transmit- and receive-in-place skbuffs. */
-	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	struct net_device *next_module;		/* NULL if PCI device */
-	void *priv_addr;
-	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
-	struct net_device_stats stats;
-	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
-
-	/* PCI configuration space information. */
-	struct pci_dev *pdev;
-	char *cb_fn_base;			/* CardBus function status addr space. */
-	int chip_id;
-
-	/* The remainder are related to chip state, mostly media selection. */
-	unsigned long in_interrupt;
-	struct timer_list timer;	/* Media selection timer. */
-	int options;				/* User-settable misc. driver options. */
-	unsigned int media_override:4, 			/* Passed-in media type. */
-		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
-		full_duplex:1, force_fd:1, autoselect:1,
-		bus_master:1,				/* Vortex can only do a fragment bus-m. */
-		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
-		hw_csums:1,				/* Has hardware checksums. */
-		tx_full:1,
-		open:1,
-		reap:1;
-	u16 status_enable;
-	u16 intr_enable;
-	u16 available_media;				/* From Wn3_Options. */
-	u16 capabilities, info1, info2;		/* Various, from EEPROM. */
-	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[2];				/* MII device addresses. */
-	u16 deferred;
-	spinlock_t lock;
-};
-
-/* The action to take with a media selection timer tick.
-   Note that we deviate from the 3Com order by checking 10base2 before AUI.
- */
-enum xcvr_types {
-	XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
-	XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
-};
-
-static struct media_table {
-	char *name;
-	unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
-		mask:8,				/* The transceiver-present bit in Wn3_Config.*/
-		next:8;				/* The media type to try next. */
-	int wait;			/* Time before we check media status. */
-} media_tbl[] = {
-  {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
-  { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
-  { "undefined", 0,			0x80, XCVR_10baseT, 10000},
-  { "10base2",   0,			0x10, XCVR_AUI,		(1*HZ)/10},
-  { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
-  { "100baseFX", Media_Lnk, 0x04, XCVR_MII,		(14*HZ)/10},
-  { "MII",		 0,			0x41, XCVR_10baseT, 3*HZ },
-  { "undefined", 0,			0x01, XCVR_10baseT, 10000},
-  { "Autonegotiate", 0,		0x41, XCVR_10baseT, 3*HZ},
-  { "MII-External",	 0,		0x41, XCVR_10baseT, 3*HZ },
-  { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
-};
-
-static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq,
-				   int chip_idx, int card_idx);
-static void vortex_up(struct net_device *dev);
-static void vortex_down(struct net_device *dev);
-static int vortex_open(struct net_device *dev);
-static void mdio_sync(long ioaddr, int bits);
-static int mdio_read(long ioaddr, int phy_id, int location);
-static void mdio_write(long ioaddr, int phy_id, int location, int value);
-static void vortex_timer(unsigned long arg);
-static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int vortex_rx(struct net_device *dev);
-static int boomerang_rx(struct net_device *dev);
-static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int vortex_close(struct net_device *dev);
-static void update_stats(long ioaddr, struct net_device *dev);
-static struct net_device_stats *vortex_get_stats(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void vortex_tx_timeout(struct net_device *dev);
-static void acpi_set_WOL(struct net_device *dev);
-
-/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
-/* Option count limit only -- unlimited interfaces are supported. */
-#define MAX_UNITS 8
-static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-
-/* A list of all installed Vortex EISA devices, for removing the driver module. */
-static struct net_device *root_vortex_eisa_dev = NULL;
-
-static int vortex_cards_found = 0;
-
-
-
-
-static void vortex_suspend (struct pci_dev *pdev)
-{
-	struct net_device *dev = pdev->driver_data;
-
-	printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
-
-	if (dev && dev->priv) {
-		struct vortex_private *vp = (struct vortex_private *)dev->priv;
-		if (vp->open) {
-			netif_device_detach(dev);
-			vortex_down(dev);
-		}
-	}
-}
-
-
-static void vortex_resume (struct pci_dev *pdev)
-{
-	struct net_device *dev = pdev->driver_data;
-
-	printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name);
-
-	if (dev && dev->priv) {
-		struct vortex_private *vp = (struct vortex_private *)dev->priv;
-		if (vp->open) {
-			vortex_up(dev);
-			netif_device_attach(dev);
-		}
-	}
-}
-
-
-/* returns count found (>= 0), or negative on error */
-static int __init vortex_eisa_init (void)
-{
-	long ioaddr;
-	int rc;
-	int orig_cards_found = vortex_cards_found;
-
-	/* Now check all slots of the EISA bus. */
-	if (!EISA_bus)
-		return 0;
-
-	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-		int device_id;
-
-		if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
-			continue;
-
-		/* Check the standard EISA ID register for an encoded '3Com'. */
-		if (inw(ioaddr + 0xC80) != 0x6d50) {
-			release_region (ioaddr, VORTEX_TOTAL_SIZE);
-			continue;
-		}
-
-		/* Check for a product that we support, 3c59{2,7} any rev. */
-		device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
-		if ((device_id & 0xFF00) != 0x5900) {
-			release_region (ioaddr, VORTEX_TOTAL_SIZE);
-			continue;
-		}
-
-		rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
-				   4, /* XXX is 4 correct eisa idx? */
-				   vortex_cards_found);
-		if (rc == 0)
-			vortex_cards_found++;
-		else
-			release_region (ioaddr, VORTEX_TOTAL_SIZE);
-	}
-
-	return vortex_cards_found - orig_cards_found;
-}
-
-
-/* returns count (>= 0), or negative on error */
-static int __devinit vortex_init_one (struct pci_dev *pdev,
-				      const struct pci_device_id *ent)
-{
-	int rc;
-
-	rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq,
-			    ent->driver_data, vortex_cards_found);
-	if (rc == 0)
-		vortex_cards_found++;
-	
-	return rc;
-}
-
-
-/* NOTE: pdev can be NULL, for the case of an EISA driver */
-static int __devinit vortex_probe1(struct pci_dev *pdev,
-				   long ioaddr, int irq,
-				   int chip_idx, int card_idx)
-{
-	struct vortex_private *vp;
-	int option;
-	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
-	int i;
-	struct net_device *dev;
-	static int printed_version = 0;
-	
-	if (!printed_version) {
-		printk (KERN_INFO "%s", version);
-		printed_version = 1;
-	}
-
-	dev = init_etherdev(NULL, sizeof(*vp));
-	if (!dev) {
-		printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
-		return -ENOMEM;
-	}
-	
-	printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
-	       dev->name,
-	       pdev ? "PCI" : "EISA",
-	       vortex_info_tbl[chip_idx].name,
-	       ioaddr);
-
-	/* private struct aligned and zeroed by init_etherdev */
-	vp = dev->priv;
-	vp->priv_addr = vp;
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	dev->mtu = mtu;
-
-	/* module list only for EISA devices */
-	if (pdev == NULL) {
-		vp->next_module = root_vortex_eisa_dev;
-		root_vortex_eisa_dev = dev;
-	}
-	
-	/* PCI-only startup logic */
-	if (pdev) {
-		/* EISA resources already marked, so only PCI needs to do this here */
-		if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size,
-				     dev->name)) {
-			printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
-				dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr);
-			kfree (dev);
-			return -EBUSY;
-		}
-
-		/* wake up and enable device */		
-		if (pci_enable_device (pdev)) {
-			printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name);
-			release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
-			kfree (dev);
-			return -EIO;
-		}
-
-		/* enable bus-mastering if necessary */		
-		if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER)
-			pci_set_master (pdev);
-	}
-
-	vp->lock = SPIN_LOCK_UNLOCKED;
-	vp->chip_id = chip_idx;
-	vp->pdev = pdev;
-
-	/* if we are a PCI driver, we store info in pdev->driver_data
-	 * instead of a module list */	
-	if (pdev)
-		pdev->driver_data = dev;
-
-	/* The lower four bits are the media type. */
-	if (dev->mem_start)
-		option = dev->mem_start;
-	else if (card_idx < MAX_UNITS)
-		option = options[card_idx];
-	else
-		option = -1;
-
-	if (option >= 0) {
-		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
-		vp->full_duplex = (option & 0x200) ? 1 : 0;
-		vp->bus_master = (option & 16) ? 1 : 0;
-	} else {
-		vp->media_override = 7;
-		vp->full_duplex = 0;
-		vp->bus_master = 0;
-	}
-	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		vp->full_duplex = 1;
-
-	vp->force_fd = vp->full_duplex;
-	vp->options = option;
-
-	/* Read the station address from the EEPROM. */
-	EL3WINDOW(0);
-	for (i = 0; i < 0x40; i++) {
-		int timer;
-#if 1 /* ifdef CARDBUS */
-		outw(0x230 + i, ioaddr + Wn0EepromCmd);
-#else
-		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
-#endif
-		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 10; timer >= 0; timer--) {
-			udelay(162);
-			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-				break;
-		}
-		eeprom[i] = inw(ioaddr + Wn0EepromData);
-	}
-	for (i = 0; i < 0x18; i++)
-		checksum ^= eeprom[i];
-	checksum = (checksum ^ (checksum >> 8)) & 0xff;
-	if (checksum != 0x00) {		/* Grrr, needless incompatible change 3Com. */
-		while (i < 0x21)
-			checksum ^= eeprom[i++];
-		checksum = (checksum ^ (checksum >> 8)) & 0xff;
-	}
-	if (checksum != 0x00)
-		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-
-	for (i = 0; i < 3; i++)
-		((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
-	for (i = 0; i < 6; i++)
-		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
-	EL3WINDOW(2);
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + i);
-
-#ifdef __sparc__
-	printk(", IRQ %s\n", __irq_itoa(dev->irq));
-#else
-	printk(", IRQ %d\n", dev->irq);
-	/* Tell them about an invalid IRQ. */
-	if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
-		printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
-			   dev->irq);
-#endif
-
-	if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
-		u32 fn_st_addr;			/* Cardbus function status space */
-		fn_st_addr = pci_resource_start (pdev, 2);
-		if (fn_st_addr)
-			vp->cb_fn_base = ioremap(fn_st_addr, 128);
-		printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n",
-			   dev->name, fn_st_addr, vp->cb_fn_base);
-	}
-
-	/* Extract our information from the EEPROM data. */
-	vp->info1 = eeprom[13];
-	vp->info2 = eeprom[15];
-	vp->capabilities = eeprom[16];
-
-	if (vp->info1 & 0x8000)
-		vp->full_duplex = 1;
-
-	{
-		char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-		union wn3_config config;
-		EL3WINDOW(3);
-		vp->available_media = inw(ioaddr + Wn3_Options);
-		if ((vp->available_media & 0xff) == 0)		/* Broken 3c916 */
-			vp->available_media = 0x40;
-		config.i = inl(ioaddr + Wn3_Config);
-		if (vortex_debug > 1)
-			printk(KERN_DEBUG "  Internal config register is %4.4x, "
-				   "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options));
-		printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-			   8 << config.u.ram_size,
-			   config.u.ram_width ? "word" : "byte",
-			   ram_split[config.u.ram_split],
-			   config.u.autoselect ? "autoselect/" : "",
-			   config.u.xcvr > XCVR_ExtMII ? "<invalid transceiver>" :
-			   media_tbl[config.u.xcvr].name);
-		vp->default_media = config.u.xcvr;
-		vp->autoselect = config.u.autoselect;
-	}
-
-	if (vp->media_override != 7) {
-		printk(KERN_INFO "  Media override to transceiver type %d (%s).\n",
-			   vp->media_override, media_tbl[vp->media_override].name);
-		dev->if_port = vp->media_override;
-	} else
-		dev->if_port = vp->default_media;
-
-	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-		int phy, phy_idx = 0;
-		EL3WINDOW(4);
-		mii_preamble_required++;
-		mii_preamble_required++;
-		mdio_read(ioaddr, 24, 1);
-		for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) {
-			int mii_status, phyx = phy & 0x1f;
-			mii_status = mdio_read(ioaddr, phyx, 1);
-			if (mii_status  &&  mii_status != 0xffff) {
-				vp->phys[phy_idx++] = phyx;
-				printk(KERN_INFO "  MII transceiver found at address %d,"
-					   " status %4x.\n", phyx, mii_status);
-				if ((mii_status & 0x0040) == 0)
-					mii_preamble_required++;
-			}
-		}
-		mii_preamble_required--;
-		if (phy_idx == 0) {
-			printk(KERN_WARNING"  ***WARNING*** No MII transceivers found!\n");
-			vp->phys[0] = 24;
-		} else {
-			vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
-			if (vp->full_duplex) {
-				/* Only advertise the FD media types. */
-				vp->advertising &= ~0x02A0;
-				mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
-			}
-		}
-	}
-
-	if (vp->capabilities & CapPwrMgmt)
-		acpi_set_WOL(dev);
-
-	if (vp->capabilities & CapBusMaster) {
-		vp->full_bus_master_tx = 1;
-		printk(KERN_INFO"  Enabling bus-master transmits and %s receives.\n",
-			   (vp->info2 & 1) ? "early" : "whole-frame" );
-		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
-	}
-
-	/* The 3c59x-specific entries in the device structure. */
-	dev->open = &vortex_open;
-	dev->hard_start_xmit = &vortex_start_xmit;
-	dev->stop = &vortex_close;
-	dev->get_stats = &vortex_get_stats;
-	dev->do_ioctl = &vortex_ioctl;
-	dev->set_multicast_list = &set_rx_mode;
-	dev->tx_timeout = &vortex_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	return 0;
-}
-
-static void wait_for_completion(struct net_device *dev, int cmd)
-{
-	int i = 2000;
-	outw(cmd, dev->base_addr + EL3_CMD);
-	while (--i > 0)
-		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
-			break;
-	if (i == 0)
-		printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
-			   dev->name, cmd);
-}
-
-static void
-vortex_up(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	union wn3_config config;
-	int i, device_id;
-
-	if (vp->pdev)
-		device_id = vp->pdev->device;
-	else
-		device_id = 0x5900; /* EISA */
-	
-	/* Before initializing select the active media port. */
-	EL3WINDOW(3);
-	config.i = inl(ioaddr + Wn3_Config);
-
-	if (vp->media_override != 7) {
-		if (vortex_debug > 1)
-			printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
-				   dev->name, vp->media_override,
-				   media_tbl[vp->media_override].name);
-		dev->if_port = vp->media_override;
-	} else if (vp->autoselect) {
-		if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)
-			dev->if_port = XCVR_NWAY;
-		else {
-			/* Find first available media type, starting with 100baseTx. */
-			dev->if_port = XCVR_100baseTx;
-			while (! (vp->available_media & media_tbl[dev->if_port].mask))
-				dev->if_port = media_tbl[dev->if_port].next;
-		}
-	} else
-		dev->if_port = vp->default_media;
-
-	init_timer(&vp->timer);
-	vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
-	vp->timer.data = (unsigned long)dev;
-	vp->timer.function = &vortex_timer;		/* timer handler */
-	add_timer(&vp->timer);
-
-	if (vortex_debug > 1)
-		printk(KERN_DEBUG "%s: Initial media type %s.\n",
-			   dev->name, media_tbl[dev->if_port].name);
-
-	vp->full_duplex = vp->force_fd;
-	config.u.xcvr = dev->if_port;
-	if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
-		outl(config.i, ioaddr + Wn3_Config);
-
-	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-		int mii_reg1, mii_reg5;
-		EL3WINDOW(4);
-		/* Read BMSR (reg1) only to clear old status. */
-		mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
-		mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
-			;					/* No MII device or no link partner report */
-		else if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
-				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
-			vp->full_duplex = 1;
-		if (vortex_debug > 1)
-			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-				   " setting %s-duplex.\n", dev->name, vp->phys[0],
-				   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
-		EL3WINDOW(3);
-	}
-
-	/* Set the full-duplex bit. */
-	outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
-
-	if (vortex_debug > 1) {
-		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
-			dev->name, config.i);
-	}
-
-	wait_for_completion(dev, TxReset);
-	wait_for_completion(dev, RxReset);
-
-	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
-	if (vortex_debug > 1) {
-		EL3WINDOW(4);
-		printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
-			   dev->name, dev->irq, inw(ioaddr + Wn4_Media));
-	}
-
-	/* Set the station address and mask in window 2 each time opened. */
-	EL3WINDOW(2);
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + i);
-	for (; i < 12; i+=2)
-		outw(0, ioaddr + i);
-	if (vp->cb_fn_base) {
-		u_short n = inw(ioaddr + Wn2_ResetOptions);
-		/* Inverted LED polarity */
-		if (device_id != 0x5257)
-			n |= 0x0010;
-		/* Inverted polarity of MII power bit */
-		if ((device_id == 0x6560) || (device_id == 0x6562) ||
-			(device_id == 0x5257))
-			n |= 0x4000;
-		outw(n, ioaddr + Wn2_ResetOptions);
-	}
-
-	if (dev->if_port == XCVR_10base2)
-		/* Start the thinnet transceiver. We should really wait 50ms...*/
-		outw(StartCoax, ioaddr + EL3_CMD);
-	if (dev->if_port != XCVR_NWAY) {
-		EL3WINDOW(4);
-		outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
-			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
-	}
-
-	/* Switch to the stats window, and clear all stats by reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	EL3WINDOW(6);
-	for (i = 0; i < 10; i++)
-		inb(ioaddr + i);
-	inw(ioaddr + 10);
-	inw(ioaddr + 12);
-	/* New: On the Vortex we must also clear the BadSSD counter. */
-	EL3WINDOW(4);
-	inb(ioaddr + 12);
-	/* ..and on the Boomerang we enable the extra statistics bits. */
-	outw(0x0040, ioaddr + Wn4_NetDiag);
-
-	/* Switch to register set 7 for normal use. */
-	EL3WINDOW(7);
-
-	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
-		vp->cur_rx = vp->dirty_rx = 0;
-		/* Initialize the RxEarly register as recommended. */
-		outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
-		outl(0x0020, ioaddr + PktStatus);
-		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
-	}
-	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
-		dev->hard_start_xmit = &boomerang_start_xmit;
-		vp->cur_tx = vp->dirty_tx = 0;
-		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
-		/* Clear the Rx, Tx rings. */
-		for (i = 0; i < RX_RING_SIZE; i++)
-			vp->rx_ring[i].status = 0;
-		for (i = 0; i < TX_RING_SIZE; i++)
-			vp->tx_skbuff[i] = 0;
-		outl(0, ioaddr + DownListPtr);
-	}
-	/* Set receiver mode: presumably accept b-case and phys addr only. */
-	set_rx_mode(dev);
-	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
-	vp->in_interrupt = 0;
-	netif_start_queue (dev);
-
-	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
-	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
-	/* Allow status bits to be seen. */
-	vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
-		(vp->full_bus_master_tx ? DownComplete : TxAvailable) |
-		(vp->full_bus_master_rx ? UpComplete : RxComplete) |
-		(vp->bus_master ? DMADone : 0);
-	vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
-		StatsFull | HostError | TxComplete | IntReq
-		| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
-	outw(vp->status_enable, ioaddr + EL3_CMD);
-	/* Ack all pending events, and set active indicator mask. */
-	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-		 ioaddr + EL3_CMD);
-	outw(vp->intr_enable, ioaddr + EL3_CMD);
-	if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
-		writel(0x8000, vp->cb_fn_base + 4);
-}
-
-static int
-vortex_open(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	int i;
-
-#ifdef CARDBUS
-	if (vp->reap)
-		return -ENODEV;
-#endif
-	/* Use the now-standard shared IRQ implementation. */
-	if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
-		return -EAGAIN;
-	}
-
-	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
-		if (vortex_debug > 2)
-			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			struct sk_buff *skb;
-			vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1]));
-			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
-			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
-			skb = dev_alloc_skb(PKT_BUF_SZ);
-			vp->rx_skbuff[i] = skb;
-			if (skb == NULL)
-				break;			/* Bad news!  */
-			skb->dev = dev;			/* Mark as being used by this device. */
-			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
-		}
-		/* Wrap the ring. */
-		vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
-	}
-	if (vp->full_bus_master_tx)
-		dev->hard_start_xmit = &boomerang_start_xmit;
-
-	vortex_up(dev);
-	vp->open = 1;
-	MOD_INC_USE_COUNT;
-
-	return 0;
-}
-
-static void vortex_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int next_tick = 60*HZ;
-	int ok = 0;
-	int media_status, mii_status, old_window;
-
-	if (vortex_debug > 1)
-		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
-			   dev->name, media_tbl[dev->if_port].name);
-
-	disable_irq(dev->irq);
-	old_window = inw(ioaddr + EL3_CMD) >> 13;
-	EL3WINDOW(4);
-	media_status = inw(ioaddr + Wn4_Media);
-	switch (dev->if_port) {
-	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
-		if (media_status & Media_LnkBeat) {
-			ok = 1;
-			if (vortex_debug > 1)
-				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
-					   dev->name, media_tbl[dev->if_port].name, media_status);
-		} else if (vortex_debug > 1)
-			printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
-				   dev->name, media_tbl[dev->if_port].name, media_status);
-		break;
-	case XCVR_MII: case XCVR_NWAY:
-		  mii_status = mdio_read(ioaddr, vp->phys[0], 1);
-		  ok = 1;
-		  if (debug > 1)
-			  printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
-					 dev->name, mii_status);
-		  if (mii_status & 0x0004) {
-			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-			  if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
-				  int duplex = (mii_reg5&0x0100) ||
-					  (mii_reg5 & 0x01C0) == 0x0040;
-				  if (vp->full_duplex != duplex) {
-					  vp->full_duplex = duplex;
-					  printk(KERN_INFO "%s: Setting %s-duplex based on MII "
-							 "#%d link partner capability of %4.4x.\n",
-							 dev->name, vp->full_duplex ? "full" : "half",
-							 vp->phys[0], mii_reg5);
-					  /* Set the full-duplex bit. */
-					  EL3WINDOW(3);
-					  outb((vp->full_duplex ? 0x20 : 0) |
-						   (dev->mtu > 1500 ? 0x40 : 0),
-						   ioaddr + Wn3_MAC_Ctrl);
-				  }
-				  next_tick = 60*HZ;
-			  }
-		  }
-		  break;
-	  default:					/* Other media types handled by Tx timeouts. */
-		if (vortex_debug > 1)
-		  printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
-				 dev->name, media_tbl[dev->if_port].name, media_status);
-		ok = 1;
-	}
-	if ( ! ok) {
-		union wn3_config config;
-
-		do {
-			dev->if_port = media_tbl[dev->if_port].next;
-		} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
-		if (dev->if_port == XCVR_Default) { /* Go back to default. */
-		  dev->if_port = vp->default_media;
-		  if (vortex_debug > 1)
-			printk(KERN_DEBUG "%s: Media selection failing, using default "
-				   "%s port.\n",
-				   dev->name, media_tbl[dev->if_port].name);
-		} else {
-			if (vortex_debug > 1)
-				printk(KERN_DEBUG "%s: Media selection failed, now trying "
-					   "%s port.\n",
-					   dev->name, media_tbl[dev->if_port].name);
-			next_tick = media_tbl[dev->if_port].wait;
-		}
-		outw((media_status & ~(Media_10TP|Media_SQE)) |
-			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
-
-		EL3WINDOW(3);
-		config.i = inl(ioaddr + Wn3_Config);
-		config.u.xcvr = dev->if_port;
-		outl(config.i, ioaddr + Wn3_Config);
-
-		outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
-			 ioaddr + EL3_CMD);
-	}
-	EL3WINDOW(old_window);
-	enable_irq(dev->irq);
-
-	if (vortex_debug > 2)
-	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
-			 dev->name, media_tbl[dev->if_port].name);
-
-	vp->timer.expires = RUN_AT(next_tick);
-	add_timer(&vp->timer);
-	if (vp->deferred)
-		outw(FakeIntr, ioaddr + EL3_CMD);
-	return;
-}
-
-static void vortex_tx_timeout(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-
-	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-		   dev->name, inb(ioaddr + TxStatus),
-		   inw(ioaddr + EL3_STATUS));
-	/* Slight code bloat to be user friendly. */
-	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
-		printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
-			   " network cable problem?\n", dev->name);
-	if (inw(ioaddr + EL3_STATUS) & IntLatch) {
-		printk(KERN_ERR "%s: Interrupt posted but not delivered --"
-			   " IRQ blocked by another device?\n", dev->name);
-		/* Bad idea here.. but we might as well handle a few events. */
-		vortex_interrupt(dev->irq, dev, 0);
-	}
-
-#if ! defined(final_version)
-	if (vp->full_bus_master_tx) {
-		int i;
-		printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
-			   "current %d.\n",
-			   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
-		printk(KERN_DEBUG "  Transmit list %8.8x vs. %p.\n",
-			   inl(ioaddr + DownListPtr),
-			   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
-		for (i = 0; i < TX_RING_SIZE; i++) {
-			printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
-				   &vp->tx_ring[i],
-				   le32_to_cpu(vp->tx_ring[i].length),
-				   le32_to_cpu(vp->tx_ring[i].status));
-		}
-	}
-#endif
-	wait_for_completion(dev, TxReset);
-
-	vp->stats.tx_errors++;
-	if (vp->full_bus_master_tx) {
-		if (vortex_debug > 0)
-			printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n",
-				   dev->name);
-		if (vp->cur_tx - vp->dirty_tx > 0  &&  inl(ioaddr + DownListPtr) == 0)
-			outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]),
-				 ioaddr + DownListPtr);
-		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
-			vp->tx_full = 0;
-			netif_start_queue (dev);
-		}
-		if (vp->tx_full)
-			netif_stop_queue (dev);
-		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
-		outw(DownUnstall, ioaddr + EL3_CMD);
-	} else
-		vp->stats.tx_dropped++;
-	
-	/* Issue Tx Enable */
-	outw(TxEnable, ioaddr + EL3_CMD);
-	dev->trans_start = jiffies;
-	
-	/* Switch to register set 7 for normal use. */
-	EL3WINDOW(7);
-}
-
-/*
- * Handle uncommon interrupt sources.  This is a separate routine to minimize
- * the cache impact.
- */
-static void
-vortex_error(struct net_device *dev, int status)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int do_tx_reset = 0;
-
-	if (status & TxComplete) {			/* Really "TxError" for us. */
-		unsigned char tx_status = inb(ioaddr + TxStatus);
-		/* Presumably a tx-timeout. We must merely re-enable. */
-		if (vortex_debug > 2
-			|| (tx_status != 0x88 && vortex_debug > 0))
-			printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
-				   dev->name, tx_status);
-		if (tx_status & 0x14)  vp->stats.tx_fifo_errors++;
-		if (tx_status & 0x38)  vp->stats.tx_aborted_errors++;
-		outb(0, ioaddr + TxStatus);
-		if (tx_status & 0x30)
-			do_tx_reset = 1;
-		else					/* Merely re-enable the transmitter. */
-			outw(TxEnable, ioaddr + EL3_CMD);
-	}
-	if (status & RxEarly) {				/* Rx early is unused. */
-		vortex_rx(dev);
-		outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
-	}
-	if (status & StatsFull) {			/* Empty statistics. */
-		static int DoneDidThat = 0;
-		if (vortex_debug > 4)
-			printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);
-		update_stats(ioaddr, dev);
-		/* HACK: Disable statistics as an interrupt source. */
-		/* This occurs when we have the wrong media type! */
-		if (DoneDidThat == 0  &&
-			inw(ioaddr + EL3_STATUS) & StatsFull) {
-			printk(KERN_WARNING "%s: Updating statistics failed, disabling "
-				   "stats as an interrupt source.\n", dev->name);
-			EL3WINDOW(5);
-			outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
-			EL3WINDOW(7);
-			DoneDidThat++;
-		}
-	}
-	if (status & IntReq) {		/* Restore all interrupt sources.  */
-		outw(vp->status_enable, ioaddr + EL3_CMD);
-		outw(vp->intr_enable, ioaddr + EL3_CMD);
-	}
-	if (status & HostError) {
-		u16 fifo_diag;
-		EL3WINDOW(4);
-		fifo_diag = inw(ioaddr + Wn4_FIFODiag);
-		printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
-			   dev->name, fifo_diag);
-		/* Adapter failure requires Tx/Rx reset and reinit. */
-		if (vp->full_bus_master_tx) {
-			/* In this case, blow the card away */
-			vortex_down(dev);
-			wait_for_completion(dev, TotalReset | 0xff);
-			vortex_up(dev);
-		} else if (fifo_diag & 0x0400)
-			do_tx_reset = 1;
-		if (fifo_diag & 0x3000) {
-			wait_for_completion(dev, RxReset);
-			/* Set the Rx filter to the current state. */
-			set_rx_mode(dev);
-			outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
-			outw(AckIntr | HostError, ioaddr + EL3_CMD);
-		}
-	}
-	if (do_tx_reset) {
-		wait_for_completion(dev, TxReset);
-		outw(TxEnable, ioaddr + EL3_CMD);
-	}
-
-}
-
-static int
-vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-
-	netif_stop_queue (dev);
-	
-	/* Put out the doubleword header... */
-	outl(skb->len, ioaddr + TX_FIFO);
-	if (vp->bus_master) {
-		/* Set the bus-master controller to transfer the packet. */
-		outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr);
-		outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
-		vp->tx_skb = skb;
-		outw(StartDMADown, ioaddr + EL3_CMD);
-		/* dev->tbusy will be cleared at the DMADone interrupt. */
-	} else {
-		/* ... and the packet rounded to a doubleword. */
-		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-		dev_kfree_skb (skb);
-		if (inw(ioaddr + TxFree) > 1536) {
-			netif_start_queue (dev);
-		} else
-			/* Interrupt us when the FIFO has room for max-sized packet. */
-			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-	}
-
-	dev->trans_start = jiffies;
-
-	/* Clear the Tx status stack. */
-	{
-		int tx_status;
-		int i = 32;
-
-		while (--i > 0	&&	(tx_status = inb(ioaddr + TxStatus)) > 0) {
-			if (tx_status & 0x3C) {		/* A Tx-disabling error occurred.  */
-				if (vortex_debug > 2)
-				  printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n",
-						 dev->name, tx_status);
-				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
-				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
-				if (tx_status & 0x30) {
-					wait_for_completion(dev, TxReset);
-				}
-				outw(TxEnable, ioaddr + EL3_CMD);
-			}
-			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
-		}
-	}
-	return 0;
-}
-
-static int
-boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-
-	netif_stop_queue (dev);
-	if (1) {
-		/* Calculate the next Tx descriptor entry. */
-		int entry = vp->cur_tx % TX_RING_SIZE;
-		struct boom_tx_desc *prev_entry =
-			&vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
-		unsigned long flags;
-
-		if (vortex_debug > 3)
-			printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
-				   dev->name, vp->cur_tx);
-		if (vp->tx_full) {
-			if (vortex_debug >0)
-				printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
-					   dev->name);
-			return 1;
-		}
-		vp->tx_skbuff[entry] = skb;
-		vp->tx_ring[entry].next = 0;
-		vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data));
-		vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
-		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
-
-		spin_lock_irqsave(&vp->lock, flags);
-		/* Wait for the stall to complete. */
-		wait_for_completion(dev, DownStall);
-		prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
-		if (inl(ioaddr + DownListPtr) == 0) {
-			outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
-			queued_packet++;
-		}
-		outw(DownUnstall, ioaddr + EL3_CMD);
-		spin_unlock_irqrestore(&vp->lock, flags);
-
-		vp->cur_tx++;
-		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
-			vp->tx_full = 1;
-			netif_stop_queue (dev);
-		} else {					/* Clear previous interrupt enable. */
-#if defined(tx_interrupt_mitigation)
-			prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
-#endif
-			netif_start_queue (dev);
-		}
-		dev->trans_start = jiffies;
-		return 0;
-	}
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = dev_id;
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr;
-	int latency, status;
-	int work_done = max_interrupt_work;
-
-	spin_lock (&vp->lock);
-	
-	ioaddr = dev->base_addr;
-	latency = inb(ioaddr + Timer);
-	status = inw(ioaddr + EL3_STATUS);
-	if (status & IntReq) {
-		status |= vp->deferred;
-		vp->deferred = 0;
-	}
-
-	if (status == 0xffff)
-		goto handler_exit;
-	if (vortex_debug > 4)
-		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
-			   dev->name, status, latency);
-	do {
-		if (vortex_debug > 5)
-				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
-					   dev->name, status);
-		if (status & RxComplete)
-			vortex_rx(dev);
-		if (status & UpComplete) {
-			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
-			boomerang_rx(dev);
-		}
-
-		if (status & TxAvailable) {
-			if (vortex_debug > 5)
-				printk(KERN_DEBUG "	TX room bit was handled.\n");
-			/* There's room in the FIFO for a full-sized packet. */
-			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue (dev);
-		}
-
-		if (status & DownComplete) {
-			unsigned int dirty_tx = vp->dirty_tx;
-
-			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
-			while (vp->cur_tx - dirty_tx > 0) {
-				int entry = dirty_tx % TX_RING_SIZE;
-				if (inl(ioaddr + DownListPtr) ==
-					virt_to_bus(&vp->tx_ring[entry]))
-					break;			/* It still hasn't been processed. */
-				if (vp->tx_skbuff[entry]) {
-					dev_kfree_skb_irq(vp->tx_skbuff[entry]);
-					vp->tx_skbuff[entry] = 0;
-				}
-				/* vp->stats.tx_packets++;  Counted below. */
-				dirty_tx++;
-			}
-			vp->dirty_tx = dirty_tx;
-			if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
-				vp->tx_full = 0;
-				netif_wake_queue (dev);
-			}
-		}
-		if (vp->tx_full)
-			netif_stop_queue (dev);
-		if (status & DMADone) {
-			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
-				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
-				if (inw(ioaddr + TxFree) > 1536) {
-					netif_wake_queue (dev);
-				} else { /* Interrupt when FIFO has room for max-sized packet. */
-					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-					netif_stop_queue (dev);
-				}
-			}
-		}
-		/* Check for all uncommon interrupts at once. */
-		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
-			if (status == 0xffff)
-				break;
-			vortex_error(dev, status);
-		}
-
-		if (--work_done < 0) {
-			printk(KERN_WARNING "%s: Too much work in interrupt, status "
-				   "%4.4x.\n", dev->name, status);
-			/* Disable all pending interrupts. */
-			do {
-				vp->deferred |= status;
-				outw(SetStatusEnb | (~vp->deferred & vp->status_enable),
-					 ioaddr + EL3_CMD);
-				outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
-			} while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
-			/* The timer will reenable interrupts. */
-			del_timer(&vp->timer);
-			vp->timer.expires = RUN_AT(1);
-			add_timer(&vp->timer);
-			break;
-		}
-		/* Acknowledge the IRQ. */
-		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-		if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
-			writel(0x8000, vp->cb_fn_base + 4);
-
-	} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-
-	if (vortex_debug > 4)
-		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
-			   dev->name, status);
-handler_exit:
-	spin_unlock (&vp->lock);
-}
-
-static int vortex_rx(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int i;
-	short rx_status;
-
-	if (vortex_debug > 5)
-		printk(KERN_DEBUG"   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
-			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
-	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
-		if (rx_status & 0x4000) { /* Error, update stats. */
-			unsigned char rx_error = inb(ioaddr + RxErrors);
-			if (vortex_debug > 2)
-				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
-			vp->stats.rx_errors++;
-			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
-			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
-			if (rx_error & 0x04)  vp->stats.rx_frame_errors++;
-			if (rx_error & 0x08)  vp->stats.rx_crc_errors++;
-			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
-		} else {
-			/* The packet length: up to 4.5K!. */
-			int pkt_len = rx_status & 0x1fff;
-			struct sk_buff *skb;
-
-			skb = dev_alloc_skb(pkt_len + 5);
-			if (vortex_debug > 4)
-				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
-					   pkt_len, rx_status);
-			if (skb != NULL) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				/* 'skb_put()' points to the start of sk_buff data area. */
-				if (vp->bus_master &&
-					! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) {
-					outl(virt_to_bus(skb_put(skb, pkt_len)),
-						 ioaddr + Wn7_MasterAddr);
-					outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
-					outw(StartDMAUp, ioaddr + EL3_CMD);
-					while (inw(ioaddr + Wn7_MasterStatus) & 0x8000)
-						;
-				} else {
-					insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
-						 (pkt_len + 3) >> 2);
-				}
-				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				vp->stats.rx_packets++;
-				/* Wait a limited time to go to next packet. */
-				for (i = 200; i >= 0; i--)
-					if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-						break;
-				continue;
-			} else if (vortex_debug)
-				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
-					   "size %d.\n", dev->name, pkt_len);
-		}
-		vp->stats.rx_dropped++;
-		wait_for_completion(dev, RxDiscard);
-	}
-
-	return 0;
-}
-
-static int
-boomerang_rx(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	int entry = vp->cur_rx % RX_RING_SIZE;
-	long ioaddr = dev->base_addr;
-	int rx_status;
-	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
-
-	if (vortex_debug > 5)
-		printk(KERN_DEBUG "  In boomerang_rx(), status %4.4x, rx_status "
-			   "%4.4x.\n",
-			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
-	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
-		if (--rx_work_limit < 0)
-			break;
-		if (rx_status & RxDError) { /* Error, update stats. */
-			unsigned char rx_error = rx_status >> 16;
-			if (vortex_debug > 2)
-				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
-			vp->stats.rx_errors++;
-			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
-			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
-			if (rx_error & 0x04)  vp->stats.rx_frame_errors++;
-			if (rx_error & 0x08)  vp->stats.rx_crc_errors++;
-			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
-		} else {
-			/* The packet length: up to 4.5K!. */
-			int pkt_len = rx_status & 0x1fff;
-			struct sk_buff *skb;
-
-			if (vortex_debug > 4)
-				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
-					   pkt_len, rx_status);
-
-			/* Check if the packet is long enough to just accept without
-			   copying to a properly sized skbuff. */
-			if (pkt_len < rx_copybreak
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				/* 'skb_put()' points to the start of sk_buff data area. */
-				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
-					   pkt_len);
-				rx_copy++;
-			} else {
-				void *temp;
-				/* Pass up the skbuff already on the Rx ring. */
-				skb = vp->rx_skbuff[entry];
-				vp->rx_skbuff[entry] = NULL;
-				temp = skb_put(skb, pkt_len);
-				/* Remove this checking code for final release. */
-				if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp)
-					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
-						   " in boomerang_rx: %p vs. %p.\n", dev->name,
-						   bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
-						   temp);
-				rx_nocopy++;
-			}
-			skb->protocol = eth_type_trans(skb, dev);
-			{					/* Use hardware checksum info. */
-				int csum_bits = rx_status & 0xee000000;
-				if (csum_bits &&
-					(csum_bits == (IPChksumValid | TCPChksumValid) ||
-					 csum_bits == (IPChksumValid | UDPChksumValid))) {
-					skb->ip_summed = CHECKSUM_UNNECESSARY;
-					rx_csumhits++;
-				}
-			}
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			vp->stats.rx_packets++;
-		}
-		entry = (++vp->cur_rx) % RX_RING_SIZE;
-	}
-	/* Refill the Rx ring buffers. */
-	for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
-		struct sk_buff *skb;
-		entry = vp->dirty_rx % RX_RING_SIZE;
-		if (vp->rx_skbuff[entry] == NULL) {
-			skb = dev_alloc_skb(PKT_BUF_SZ);
-			if (skb == NULL)
-				break;			/* Bad news!  */
-			skb->dev = dev;			/* Mark as being used by this device. */
-			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail));
-			vp->rx_skbuff[entry] = skb;
-		}
-		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
-		outw(UpUnstall, ioaddr + EL3_CMD);
-	}
-	return 0;
-}
-
-static void
-vortex_down(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-
-	netif_stop_queue (dev);
-
-	del_timer(&vp->timer);
-
-	/* Turn off statistics ASAP.  We update vp->stats below. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-
-	/* Disable the receiver and transmitter. */
-	outw(RxDisable, ioaddr + EL3_CMD);
-	outw(TxDisable, ioaddr + EL3_CMD);
-
-	if (dev->if_port == XCVR_10base2)
-		/* Turn off thinnet power.  Green! */
-		outw(StopCoax, ioaddr + EL3_CMD);
-
-	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
-	update_stats(ioaddr, dev);
-	if (vp->full_bus_master_rx)
-		outl(0, ioaddr + UpListPtr);
-	if (vp->full_bus_master_tx)
-		outl(0, ioaddr + DownListPtr);
-
-	if (vp->capabilities & CapPwrMgmt)
-		acpi_set_WOL(dev);
-}
-
-static int
-vortex_close(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int i;
-
-	if (netif_device_present(dev))
-		vortex_down(dev);
-
-	if (vortex_debug > 1) {
-		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
-			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
-		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
-			   " tx_queued %d Rx pre-checksummed %d.\n",
-			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
-	}
-
-	free_irq(dev->irq, dev);
-
-	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
-		for (i = 0; i < RX_RING_SIZE; i++)
-			if (vp->rx_skbuff[i]) {
-				dev_kfree_skb(vp->rx_skbuff[i]);
-				vp->rx_skbuff[i] = 0;
-			}
-	}
-	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
-		for (i = 0; i < TX_RING_SIZE; i++)
-			if (vp->tx_skbuff[i]) {
-				dev_kfree_skb(vp->tx_skbuff[i]);
-				vp->tx_skbuff[i] = 0;
-			}
-	}
-
-	MOD_DEC_USE_COUNT;
-	vp->open = 0;
-	return 0;
-}
-
-static struct net_device_stats *vortex_get_stats(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	unsigned long flags;
-
-	if (netif_device_present(dev)) {
-		spin_lock_irqsave (&vp->lock, flags);
-		update_stats(dev->base_addr, dev);
-		spin_unlock_irqrestore (&vp->lock, flags);
-	}
-	return &vp->stats;
-}
-
-/*  Update statistics.
-	Unlike with the EL3 we need not worry about interrupts changing
-	the window setting from underneath us, but we must still guard
-	against a race condition with a StatsUpdate interrupt updating the
-	table.  This is done by checking that the ASM (!) code generated uses
-	atomic updates with '+='.
-	*/
-static void update_stats(long ioaddr, struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	int old_window = inw(ioaddr + EL3_CMD);
-
-	if (old_window == 0xffff)	/* Chip suspended or ejected. */
-		return;
-	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
-	/* Switch to the stats window, and read everything. */
-	EL3WINDOW(6);
-	vp->stats.tx_carrier_errors		+= inb(ioaddr + 0);
-	vp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
-	/* Multiple collisions. */		inb(ioaddr + 2);
-	vp->stats.collisions			+= inb(ioaddr + 3);
-	vp->stats.tx_window_errors		+= inb(ioaddr + 4);
-	vp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
-	vp->stats.tx_packets			+= inb(ioaddr + 6);
-	vp->stats.tx_packets			+= (inb(ioaddr + 9)&0x30) << 4;
-	/* Rx packets	*/				inb(ioaddr + 7);   /* Must read to clear */
-	/* Tx deferrals */				inb(ioaddr + 8);
-	/* Don't bother with register 9, an extension of registers 6&7.
-	   If we do use the 6&7 values the atomic update assumption above
-	   is invalid. */
-	vp->stats.rx_bytes += inw(ioaddr + 10);
-	vp->stats.tx_bytes += inw(ioaddr + 12);
-	/* New: On the Vortex we must also clear the BadSSD counter. */
-	EL3WINDOW(4);
-	inb(ioaddr + 12);
-
-	{
-		u8 up = inb(ioaddr + 13);
-		vp->stats.rx_bytes += (up & 0x0f) << 16;
-		vp->stats.tx_bytes += (up & 0xf0) << 12;
-	}
-
-	/* We change back to window 7 (not 1) with the Vortex. */
-	EL3WINDOW(old_window >> 13);
-	return;
-}
-
-static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	u16 *data = (u16 *)&rq->ifr_data;
-	int phy = vp->phys[0] & 0x1f;
-
-	switch(cmd) {
-	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		data[0] = phy;
-	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		EL3WINDOW(4);
-		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-		return 0;
-	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		EL3WINDOW(4);
-		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-/* Pre-Cyclone chips have no documented multicast filter, so the only
-   multicast setting is to receive all multicast frames.  At least
-   the chip has a very clean way to set the mode, unlike many others. */
-static void set_rx_mode(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	int new_mode;
-
-	if (dev->flags & IFF_PROMISC) {
-		if (vortex_debug > 0)
-			printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
-		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
-	} else	if ((dev->mc_list)  ||  (dev->flags & IFF_ALLMULTI)) {
-		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
-	} else
-		new_mode = SetRxFilter | RxStation | RxBroadcast;
-
-	outw(new_mode, ioaddr + EL3_CMD);
-}
-
-/* MII transceiver control section.
-   Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details. */
-
-/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues. */
-#define mdio_delay() inl(mdio_addr)
-
-#define MDIO_SHIFT_CLK	0x01
-#define MDIO_DIR_WRITE	0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ	0x02
-#define MDIO_ENB_IN		0x00
-
-/* Generate the preamble required for initial synchronization and
-   a few older transceivers. */
-static void mdio_sync(long ioaddr, int bits)
-{
-	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
-	/* Establish sync by sending at least 32 logic ones. */
-	while (-- bits >= 0) {
-		outw(MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-}
-
-static int mdio_read(long ioaddr, int phy_id, int location)
-{
-	int i;
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	unsigned int retval = 0;
-	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
-	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
-
-	/* Shift the read command bits out. */
-	for (i = 14; i >= 0; i--) {
-		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		outw(dataval, mdio_addr);
-		mdio_delay();
-		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outw(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
-}
-
-static void mdio_write(long ioaddr, int phy_id, int location, int value)
-{
-	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
-	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-	int i;
-
-	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
-
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		outw(dataval, mdio_addr);
-		mdio_delay();
-		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Leave the interface idle. */
-	for (i = 1; i >= 0; i--) {
-		outw(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-
-	return;
-}
-
-/* ACPI: Advanced Configuration and Power Interface. */
-/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
-static void acpi_set_WOL(struct net_device *dev)
-{
-	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-
-	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
-	EL3WINDOW(7);
-	outw(2, ioaddr + 0x0c);
-	/* The RxFilter must accept the WOL frames. */
-	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
-	outw(RxEnable, ioaddr + EL3_CMD);
-	/* Change the power state to D3; RxEnable doesn't take effect. */
-	pci_write_config_word(vp->pdev, 0xe0, 0x8103);
-}
-
-
-static void __devexit vortex_remove_one (struct pci_dev *pdev)
-{
-	struct net_device *dev = pdev->driver_data;
-	struct vortex_private *vp;
-
-	if (!dev)
-		return;
-
-	vp = (void *)(dev->priv);
-
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	unregister_netdev(dev);
-	outw(TotalReset, dev->base_addr + EL3_CMD);
-	release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size);
-	kfree(dev);
-}
-
-
-static struct pci_driver vortex_driver = {
-	name:		"3c575_cb",
-	probe:		vortex_init_one,
-	remove:		vortex_remove_one,
-	suspend:	vortex_suspend,
-	resume:		vortex_resume,
-	id_table:	vortex_pci_tbl,
-};
-
-
-static int vortex_have_pci = 0;
-static int vortex_have_eisa = 0;
-
-
-static int __init vortex_init (void)
-{
-	int rc;
-	
-	MOD_INC_USE_COUNT;
-	
-	rc = pci_module_init (&vortex_driver);
-	if (rc < 0)
-		goto out;
-	if (rc > 0)
-		vortex_have_pci = 1;
-
-	rc = vortex_eisa_init ();
-	if (rc < 0)
-		goto out;
-	if (rc > 0)
-		vortex_have_eisa = 1;
-
-out:
-	MOD_DEC_USE_COUNT;
-	return rc;
-}
-
-
-static void __exit vortex_eisa_cleanup (void)
-{
-	struct net_device *dev, *tmp;
-	struct vortex_private *vp;
-	long ioaddr;
-
-	dev = root_vortex_eisa_dev;
-
-	while (dev) {
-		vp = dev->priv;
-		ioaddr = dev->base_addr;
-
-		unregister_netdev (dev);
-		outw (TotalReset, ioaddr + EL3_CMD);
-		release_region (ioaddr, VORTEX_TOTAL_SIZE);
-
-		tmp = dev;
-		dev = vp->next_module;
-
-		kfree (tmp);
-	}
-}
-
-
-static void __exit vortex_cleanup (void)
-{
-	if (vortex_have_pci)
-		pci_unregister_driver (&vortex_driver);
-	if (vortex_have_eisa)
-		vortex_eisa_cleanup ();
-}
-
-
-module_init(vortex_init);
-module_exit(vortex_cleanup);
-
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c"
- *  cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.3.99-pre5/linux/drivers/net/pcmcia/Config.in	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/pcmcia/Config.in	Mon Apr 24 15:17:06 2000
@@ -18,7 +18,7 @@
    dep_tristate '  IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
 
    if [ "$CONFIG_CARDBUS" = "y" ]; then
-      dep_tristate '  3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
+      comment '  3Com 3c575 moved to Ethernet 10/100 menu'
       tristate '  Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP
    fi
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- v2.3.99-pre5/linux/drivers/net/pcmcia/Makefile	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/pcmcia/Makefile	Mon Apr 24 15:17:06 2000
@@ -36,7 +36,6 @@
 obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_cs.o
 
 # Cardbus client drivers
-obj-$(CONFIG_PCMCIA_3C575)	+= 3c575_cb.o
 obj-$(CONFIG_PCMCIA_XIRTULIP)	+= xircom_tulip_cb.o
 
 obj-$(CONFIG_PCMCIA_IBMTR)	+= ibmtr_cs.o
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.3.99-pre5/linux/drivers/net/pcmcia/ray_cs.c	Tue Mar 14 19:10:39 2000
+++ linux/drivers/net/pcmcia/ray_cs.c	Wed Apr 12 09:16:31 2000
@@ -1494,16 +1494,19 @@
     dev_link_t *link;
     ray_dev_t *local = (ray_dev_t *)dev->priv;
     
+    MOD_INC_USE_COUNT;
+
     DEBUG(1, "ray_open('%s')\n", dev->name);
 
     for (link = dev_list; link; link = link->next)
         if (link->priv == dev) break;
-    if (!DEV_OK(link))
+    if (!DEV_OK(link)) {
+        MOD_DEC_USE_COUNT;
         return -ENODEV;
+    }
 
     if (link->open == 0) local->num_multi = 0;
     link->open++;
-    MOD_INC_USE_COUNT;
 
     if (sniffer) netif_stop_queue(dev);
     else         netif_start_queue(dev);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c
--- v2.3.99-pre5/linux/drivers/net/pcmcia/xircom_tulip_cb.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/pcmcia/xircom_tulip_cb.c	Fri Apr 21 16:08:52 2000
@@ -3132,7 +3132,7 @@
 	return 0;
 }
 
-static __exit void tulip_exit(void)
+static void __exit tulip_exit(void)
 {
 	pci_unregister_driver(&tulip_ops);
 }
@@ -3143,7 +3143,6 @@
 
 /*
  * Local variables:
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/"
  *  c-indent-level: 4
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.3.99-pre5/linux/drivers/net/plip.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/plip.c	Wed Apr 12 09:38:57 2000
@@ -687,11 +687,12 @@
 			return ERROR;
 		}
 		/* Malloc up new buffer. */
-		rcv->skb = dev_alloc_skb(rcv->length.h);
+		rcv->skb = dev_alloc_skb(rcv->length.h + 2);
 		if (rcv->skb == NULL) {
 			printk(KERN_ERR "%s: Memory squeeze.\n", dev->name);
 			return ERROR;
 		}
+		skb_reserve(rcv->skb, 2);	/* Align IP on 16 byte boundaries */
 		skb_put(rcv->skb,rcv->length.h);
 		rcv->skb->dev = dev;
 		rcv->state = PLIP_PK_DATA;
@@ -989,7 +990,7 @@
 
 	switch (nl->connection) {
 	case PLIP_CN_CLOSING:
-		netif_start_queue (dev);
+		netif_wake_queue (dev);
 	case PLIP_CN_NONE:
 	case PLIP_CN_SEND:
 		dev->last_rx = jiffies;
@@ -1035,7 +1036,7 @@
 	if (skb->len > dev->mtu + dev->hard_header_len) {
 		printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len);
 		netif_start_queue (dev);
-		return 0;
+		return 1;
 	}
 
 	if (net_debug > 2)
@@ -1054,7 +1055,6 @@
 	mark_bh(IMMEDIATE_BH);
 	spin_unlock_irq(&nl->lock);
 	
-	netif_start_queue (dev);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- v2.3.99-pre5/linux/drivers/net/ppp_async.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/ppp_async.c	Fri Apr 21 13:31:10 2000
@@ -290,6 +290,7 @@
 	return err;
 }
 
+/* No kernel lock - fine */
 static unsigned int
 ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.3.99-pre5/linux/drivers/net/ppp_generic.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/ppp_generic.c	Fri Apr 21 16:19:45 2000
@@ -19,7 +19,7 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000406==
+ * ==FILEVERSION 20000417==
  */
 
 #include <linux/config.h>
@@ -206,7 +206,7 @@
 			      size_t count);
 static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
 				unsigned int cmd, unsigned long arg);
-static void ppp_xmit_process(struct ppp *ppp, int wakeup);
+static void ppp_xmit_process(struct ppp *ppp);
 static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
 static void ppp_push(struct ppp *ppp);
 static void ppp_channel_push(struct channel *pch);
@@ -427,7 +427,7 @@
 
 	switch (pf->kind) {
 	case INTERFACE:
-		ppp_xmit_process(PF_TO_PPP(pf), 0);
+		ppp_xmit_process(PF_TO_PPP(pf));
 		break;
 	case CHANNEL:
 		ppp_channel_push(PF_TO_CHANNEL(pf));
@@ -440,6 +440,7 @@
 	return ret;
 }
 
+/* No kernel lock - fine */
 static unsigned int ppp_poll(struct file *file, poll_table *wait)
 {
 	struct ppp_file *pf = (struct ppp_file *) file->private_data;
@@ -774,7 +775,7 @@
 
 	netif_stop_queue(dev);
 	skb_queue_tail(&ppp->file.xq, skb);
-	ppp_xmit_process(ppp, 0);
+	ppp_xmit_process(ppp);
 	return 0;
 
  outf:
@@ -860,13 +861,12 @@
  * that can now be done.
  */
 static void
-ppp_xmit_process(struct ppp *ppp, int wakeup)
+ppp_xmit_process(struct ppp *ppp)
 {
 	struct sk_buff *skb;
 
 	ppp_xmit_lock(ppp);
-	if (wakeup)
-		ppp_push(ppp);
+	ppp_push(ppp);
 	while (ppp->xmit_pending == 0
 	       && (skb = skb_dequeue(&ppp->file.xq)) != 0)
 		ppp_send_frame(ppp, skb);
@@ -1018,14 +1018,12 @@
 		spin_lock_bh(&pch->downl);
 		if (pch->chan) {
 			if (pch->chan->ops->start_xmit(pch->chan, skb))
-				skb = 0;
+				ppp->xmit_pending = 0;
 		} else {
 			/* channel got unregistered */
 			kfree_skb(skb);
-			skb = 0;
-		}
-		if (skb_queue_len(&pch->file.xq) == 0 && skb == 0)
 			ppp->xmit_pending = 0;
+		}
 		spin_unlock_bh(&pch->downl);
 		return;
 	}
@@ -1196,6 +1194,7 @@
 ppp_channel_push(struct channel *pch)
 {
 	struct sk_buff *skb;
+	struct ppp *ppp;
 
 	spin_lock_bh(&pch->downl);
 	if (pch->chan != 0) {
@@ -1212,6 +1211,14 @@
 		skb_queue_purge(&pch->file.xq);
 	}
 	spin_unlock_bh(&pch->downl);
+	/* see if there is anything from the attached unit to be sent */
+	if (skb_queue_len(&pch->file.xq) == 0) {
+		read_lock_bh(&pch->upl);
+		ppp = pch->ppp;
+		if (ppp != 0)
+			ppp_xmit_process(ppp);
+		read_unlock_bh(&pch->upl);
+	}
 }
 
 /*
@@ -1792,18 +1799,10 @@
 ppp_output_wakeup(struct ppp_channel *chan)
 {
 	struct channel *pch = chan->ppp;
-	struct ppp *ppp;
 
 	if (pch == 0)
 		return;
 	ppp_channel_push(pch);
-	if (skb_queue_len(&pch->file.xq) == 0) {
-		read_lock_bh(&pch->upl);
-		ppp = pch->ppp;
-		if (ppp != 0)
-			ppp_xmit_process(ppp, 1);
-		read_unlock_bh(&pch->upl);
-	}
 }
 
 /*
@@ -1830,6 +1829,7 @@
 	return ppp_file_write(&pch->file, buf, count);
 }
 
+/* No kernel lock - fine */
 unsigned int
 ppp_channel_poll(struct ppp_channel *chan, struct file *file, poll_table *wait)
 {
@@ -2376,6 +2376,7 @@
 {
 	struct ppp *ppp;
 	int err = -EINVAL;
+	int dead;
 
 	write_lock_bh(&pch->upl);
 	ppp = pch->ppp;
@@ -2385,12 +2386,12 @@
 		ppp_lock(ppp);
 		list_del(&pch->clist);
 		--ppp->n_channels;
-		if (ppp->dev == 0 && ppp->n_channels == 0)
+		dead = ppp->dev == 0 && ppp->n_channels == 0;
+		ppp_unlock(ppp);
+		if (dead)
 			/* Last disconnect from a ppp unit
 			   that is already dead: free it. */
 			kfree(ppp);
-		else
-			ppp_unlock(ppp);
 		err = 0;
 	}
 	write_unlock_bh(&pch->upl);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c
--- v2.3.99-pre5/linux/drivers/net/ppp_synctty.c	Tue Apr 11 15:09:17 2000
+++ linux/drivers/net/ppp_synctty.c	Fri Apr 21 13:32:06 2000
@@ -329,6 +329,7 @@
 	return err;
 }
 
+/* No kernel lock - fine */
 static unsigned int
 ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c
--- v2.3.99-pre5/linux/drivers/net/rrunner.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/rrunner.c	Fri Apr 21 16:08:45 2000
@@ -25,6 +25,7 @@
 #define RX_DMA_SKBUFF 1
 #define PKT_COPY_THRESHOLD 512
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/types.h>
@@ -166,7 +167,7 @@
 		rrpriv = (struct rr_private *)dev->priv;
 		memset(rrpriv, 0, sizeof(*rrpriv));
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		spin_lock_init(&rrpriv->lock);
 #endif
 		sprintf(rrpriv->name, "RoadRunner serial HIPPI");
@@ -1650,6 +1651,6 @@
 
 /*
  * Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
+ * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
  * End:
  */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c
--- v2.3.99-pre5/linux/drivers/net/rtl8129.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/rtl8129.c	Fri Apr 21 16:08:52 2000
@@ -1460,7 +1460,6 @@
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/setup.c linux/drivers/net/setup.c
--- v2.3.99-pre5/linux/drivers/net/setup.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/setup.c	Fri Apr 21 16:08:45 2000
@@ -28,6 +28,7 @@
 extern int sdla_setup(void); 
 extern int sdla_c_setup(void); 
 extern int comx_init(void);
+extern int lmc_setup(void);
 
 extern int abyss_probe(void);
 extern int madgemc_probe(void);
@@ -81,6 +82,9 @@
 	 *	SLHC if present needs attaching so other people see it
 	 *	even if not opened.
 	 */
+#if defined(CONFIG_LANMEDIA)
+	{lmc_setup, 0},
+#endif
 	 
 #ifdef CONFIG_INET	 
 #if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.3.99-pre5/linux/drivers/net/shaper.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/shaper.c	Wed Apr 26 12:13:17 2000
@@ -64,6 +64,9 @@
  *              Device statistics (tx_pakets, tx_bytes,
  *              tx_drops: queue_over_time and collisions: max_queue_exceded)
  *                               1999/06/18 Jordi Murgo <savage@apostols.org>
+ *
+ *		Use skb->cb for private data.
+ *				 2000/03 Andi Kleen
  */
  
 #include <linux/config.h>
@@ -85,6 +88,15 @@
 #include <net/arp.h>
 #include <linux/if_shaper.h>
 
+struct shaper_cb { 
+	__u32		shapelatency;		/* Latency on frame */
+	__u32		shapeclock;		/* Time it should go out */
+	__u32		shapelen;		/* Frame length in clocks */
+	__u32		shapestamp;		/* Stamp for shaper    */
+	__u16		shapepend;		/* Pending */
+}; 
+#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb))
+
 int sh_debug;		/* Debug flag */
 
 #define SHAPER_BANNER	"CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"
@@ -149,7 +161,7 @@
 static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
 {
  	struct sk_buff *ptr;
- 	
+   
  	/*
  	 *	Get ready to work on this shaper. Lock may fail if its
  	 *	an interrupt and locked.
@@ -163,25 +175,25 @@
  	 *	Set up our packet details
  	 */
  	 
- 	skb->shapelatency=0;
- 	skb->shapeclock=shaper->recovery;
- 	if(time_before(skb->shapeclock, jiffies))
- 		skb->shapeclock=jiffies;
+ 	SHAPERCB(skb)->shapelatency=0;
+ 	SHAPERCB(skb)->shapeclock=shaper->recovery;
+ 	if(time_before(SHAPERCB(skb)->shapeclock, jiffies))
+ 		SHAPERCB(skb)->shapeclock=jiffies;
  	skb->priority=0;	/* short term bug fix */
- 	skb->shapestamp=jiffies;
+ 	SHAPERCB(skb)->shapestamp=jiffies;
  	
  	/*
  	 *	Time slots for this packet.
  	 */
  	 
- 	skb->shapelen= shaper_clocks(shaper,skb);
+ 	SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb);
  	
 #ifdef SHAPER_COMPLEX /* and broken.. */
 
  	while(ptr && ptr!=(struct sk_buff *)&shaper->sendq)
  	{
  		if(ptr->pri<skb->pri 
- 			&& jiffies - ptr->shapeclock < SHAPER_MAXSLIP)
+ 			&& jiffies - SHAPERCB(ptr)->shapeclock < SHAPER_MAXSLIP)
  		{
  			struct sk_buff *tmp=ptr->prev;
 
@@ -190,14 +202,14 @@
  			 *	of the new frame.
  			 */
 
- 			ptr->shapeclock+=skb->shapelen;
- 			ptr->shapelatency+=skb->shapelen;
+ 			SHAPERCB(ptr)->shapeclock+=SHAPERCB(skb)->shapelen;
+ 			SHAPERCB(ptr)->shapelatency+=SHAPERCB(skb)->shapelen;
 
  			/*
  			 *	The packet may have slipped so far back it
  			 *	fell off.
  			 */
- 			if(ptr->shapelatency > SHAPER_LATENCY)
+ 			if(SHAPERCB(ptr)->shapelatency > SHAPER_LATENCY)
  			{
  				skb_unlink(ptr);
  				dev_kfree_skb(ptr);
@@ -218,7 +230,7 @@
  		 *	this loop.
  		 */
  		for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=ptr; tmp=tmp->next)
- 			skb->shapeclock+=tmp->shapelen;
+ 			SHAPERCB(skb)->shapeclock+=tmp->shapelen;
  		skb_append(ptr,skb);
  	}
 #else
@@ -230,11 +242,11 @@
 		 */
 		for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && 
 			tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next)
-			skb->shapeclock+=tmp->shapelen;
+			SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen;
 		/*
 		 *	Queue over time. Spill packet.
 		 */
-		if(skb->shapeclock-jiffies > SHAPER_LATENCY) {
+		if(SHAPERCB(skb)->shapeclock-jiffies > SHAPER_LATENCY) {
 			dev_kfree_skb(skb);
 			shaper->stats.tx_dropped++;
 		} else
@@ -325,22 +337,23 @@
 		 */
 		 
 		if(sh_debug)
-			printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies);
-		if(time_before_eq(skb->shapeclock - jiffies, SHAPER_BURST))
+			printk("Clock = %d, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies);
+		if(time_before_eq(SHAPERCB(skb)->shapeclock - jiffies, SHAPER_BURST))
 		{
 			/*
 			 *	Pull the frame and get interrupts back on.
 			 */
 			 
 			skb_unlink(skb);
-			if (shaper->recovery < skb->shapeclock + skb->shapelen)
-				shaper->recovery = skb->shapeclock + skb->shapelen;
+			if (shaper->recovery < 
+			    SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen)
+				shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen;
 			/*
 			 *	Pass on to the physical target device via
 			 *	our low level packet thrower.
 			 */
 			
-			skb->shapepend=0;
+			SHAPERCB(skb)->shapepend=0;
 			shaper_queue_xmit(shaper, skb);	/* Fire */
 		}
 		else
@@ -352,7 +365,7 @@
 	 */
 	 
 	if(skb!=NULL)
-		mod_timer(&shaper->timer, skb->shapeclock);
+		mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
 
 	clear_bit(0, &shaper->locked);
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.3.99-pre5/linux/drivers/net/starfire.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/starfire.c	Fri Apr 21 16:08:45 2000
@@ -1375,7 +1375,6 @@
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c starfire.c"
  *  c-indent-level: 4
  *  c-basic-offset: 4
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c
--- v2.3.99-pre5/linux/drivers/net/tulip/21142.c	Mon Mar 27 08:08:26 2000
+++ linux/drivers/net/tulip/21142.c	Fri Apr 14 10:09:00 2000
@@ -88,8 +88,10 @@
 		next_tick = 3*HZ;
 	}
 
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
+	/* mod_timer synchronizes us with potential add_timer calls
+	 * from interrupts.
+	 */
+	mod_timer(&tp->timer, RUN_AT(next_tick));
 }
 
 
@@ -108,7 +110,10 @@
 			   dev->name, csr14);
 	outl(0x0001, ioaddr + CSR13);
 	outl(csr14, ioaddr + CSR14);
-	tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+	if (tp->chip_id == PNIC2)
+	  tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+	else 
+	  tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
 	tulip_outl_CSR6(tp, tp->csr6);
 	if (tp->mtable  &&  tp->mtable->csr15dir) {
 		outl(tp->mtable->csr15dir, ioaddr + CSR15);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c
--- v2.3.99-pre5/linux/drivers/net/tulip/timer.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/net/tulip/timer.c	Fri Apr 14 10:09:00 2000
@@ -171,8 +171,10 @@
 	}
 	break;
 	}
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
+	/* mod_timer synchronizes us with potential add_timer calls
+	 * from interrupts.
+	 */
+	mod_timer(&tp->timer, RUN_AT(next_tick));
 }
 
 
@@ -188,8 +190,7 @@
 			   inl(ioaddr + CSR12));
 	}
 	if (next_tick) {
-		tp->timer.expires = RUN_AT(next_tick);
-		add_timer(&tp->timer);
+		mod_timer(&tp->timer, RUN_AT(next_tick));
 	}
 }
 
@@ -205,7 +206,9 @@
 		printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
 			   "%4.4x.\n",
 			   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
+	/* mod_timer synchronizes us with potential add_timer calls
+	 * from interrupts.
+	 */
+	mod_timer(&tp->timer, RUN_AT(next_tick));
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h
--- v2.3.99-pre5/linux/drivers/net/tulip/tulip.h	Mon Mar 27 08:08:27 2000
+++ linux/drivers/net/tulip/tulip.h	Wed Apr 12 09:16:31 2000
@@ -19,6 +19,22 @@
 #include <linux/timer.h>
 #include <asm/io.h>
 
+
+
+/* undefine, or define to various debugging levels (>4 == obscene levels) */
+#undef TULIP_DEBUG
+
+
+#ifdef TULIP_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+
+
+
 struct tulip_chip_table {
 	char *chip_name;
 	int io_size;
@@ -148,6 +164,38 @@
 	csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl),
 };
 
+enum t21143_csr6_bits {
+	csr6_sc = (1<<31),
+	csr6_ra = (1<<30),
+	csr6_ign_dest_msb = (1<<26),
+	csr6_mbo = (1<<25),
+	csr6_scr = (1<<24),
+	csr6_pcs = (1<<23),
+	csr6_ttm = (1<<22),
+	csr6_sf = (1<<21),
+	csr6_hbd = (1<<19),
+	csr6_ps = (1<<18),
+	csr6_ca = (1<<17),
+	csr6_st = (1<<13),
+	csr6_fc = (1<<12),
+	csr6_om_int_loop = (1<<10),
+	csr6_om_ext_loop = (1<<11),
+	csr6_fd = (1<<9),
+	csr6_pm = (1<<7),
+	csr6_pr = (1<<6),
+	csr6_sb = (1<<5),
+	csr6_if = (1<<4),
+	csr6_pb = (1<<3),
+	csr6_ho = (1<<2),
+	csr6_sr = (1<<1),
+	csr6_hp = (1<<0),
+	
+	csr6_mask_capture = (csr6_sc | csr6_ca),
+	csr6_mask_defstate = (csr6_mask_capture | csr6_mbo),
+	csr6_mask_fullcap = (csr6_mask_defstate | csr6_hbd |
+			     csr6_ps | (3<<14) | csr6_fd),
+};
+
 
 /* Keep the ring sizes a power of two for efficiency.
    Making the Tx ring too large decreases the effectiveness of channel
@@ -247,6 +295,7 @@
 	struct sk_buff	*skb;
 	dma_addr_t	mapping;
 };
+
 
 struct tulip_private {
 	const char *product_name;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- v2.3.99-pre5/linux/drivers/net/tulip/tulip_core.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/net/tulip/tulip_core.c	Fri Apr 14 10:09:00 2000
@@ -19,7 +19,7 @@
 
 */
 
-static const char version[] = "Linux Tulip driver version 0.9.4.2 (Mar 21, 2000)\n";
+static const char version[] = "Linux Tulip driver version 0.9.4.3 (Apr 14, 2000)\n";
 
 #include <linux/module.h>
 #include "tulip.h"
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.3.99-pre5/linux/drivers/net/via-rhine.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/net/via-rhine.c	Fri Apr 21 16:08:45 2000
@@ -32,10 +32,15 @@
 	- Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
 
 	LK1.1.3:
-	- Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c code)
-	                 update "Theory of Operation" with softnet/locking changes
+	- Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c
+			 code) update "Theory of Operation" with
+			 softnet/locking changes
 	- Dave Miller: PCI DMA and endian fixups
 	- Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
+
+	LK1.1.4:
+	- Urban Widmark: fix gcc 2.95.2 problem and
+	                 remove writel's to fixed address 0x7c
 */
 
 /* A few user-configurable values.   These may be modified when a driver
@@ -105,7 +110,7 @@
 #include <asm/io.h>
 
 static const char *versionA __devinitdata =
-"via-rhine.c:v1.03a-LK1.1.3  3/23/2000  Written by Donald Becker\n";
+"via-rhine.c:v1.03a-LK1.1.4  3/28/2000  Written by Donald Becker\n";
 static const char *versionB __devinitdata =
 "  http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
 
@@ -774,6 +779,7 @@
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	int i;
+	dma_addr_t next = np->rx_ring_dma;
 
 	np->cur_rx = np->cur_tx = 0;
 	np->dirty_rx = np->dirty_tx = 0;
@@ -784,8 +790,8 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].rx_status = 0;
 		np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
-		np->rx_ring[i].next_desc =
-			cpu_to_le32(np->rx_ring_dma + sizeof(struct rx_desc)*(i+1));
+		next += sizeof(struct rx_desc);
+		np->rx_ring[i].next_desc = cpu_to_le32(next);
 		np->rx_skbuff[i] = 0;
 	}
 	/* Mark the last entry as wrapping the ring. */
@@ -806,13 +812,15 @@
 		np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]);
 		np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
 	}
+	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
+	next = np->tx_ring_dma;
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_skbuff[i] = 0;
 		np->tx_ring[i].tx_status = 0;
 		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
-		np->tx_ring[i].next_desc =
-			cpu_to_le32(np->tx_ring_dma + sizeof(struct tx_desc)*(i+1));
+		next += sizeof(struct tx_desc);
+		np->tx_ring[i].next_desc = cpu_to_le32(next);
 		np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
 	}
 	np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
@@ -1097,7 +1105,6 @@
 	if (intr_status & IntrStatsMax) {
 		np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
 		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
-		writel(0, RxMissed);
 	}
 	if (intr_status & IntrTxAbort) {
 		/* Stats counted in Tx-done handler, just restart Tx. */
@@ -1129,7 +1136,6 @@
 	   non-critical. */
 	np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
 	np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
-	writel(0, RxMissed);
 
 	return &np->stats;
 }
@@ -1313,7 +1319,6 @@
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in
--- v2.3.99-pre5/linux/drivers/net/wan/Config.in	Mon Mar 27 08:08:27 2000
+++ linux/drivers/net/wan/Config.in	Fri Apr 21 16:08:45 2000
@@ -21,6 +21,12 @@
 	#
 
 	tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX
+
+        #
+        # Lan Media's board. Currently 1000, 1200, 5200, 5245
+        #
+        tristate 'LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA
+ 
 	if [ "$CONFIG_COMX" != "n" ]; then
 		dep_tristate '  Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX
 		dep_tristate '  Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile
--- v2.3.99-pre5/linux/drivers/net/wan/Makefile	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/wan/Makefile	Fri Apr 21 16:08:45 2000
@@ -12,7 +12,7 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) lmc
 
 L_TARGET := wan.a
 L_OBJS   :=
@@ -118,6 +118,19 @@
   M_OBJS += cosa.o
   endif
 endif
+
+ifeq ($(CONFIG_LANMEDIA),y)
+  SUB_DIRS += lmc
+  MOD_IN_SUB_DIRS += lmc
+  L_OBJS += lmc/lmc.o
+  CONFIG_SYNCPPP_BUILTIN = y
+else
+  ifeq ($(CONFIG_LANMEDIA),m)
+  CONFIG_SYNCPPP_MODULE = y
+  MOD_IN_SUB_DIRS += lmc
+  endif
+endif
+ 
 
 # If anything built-in uses syncppp, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c
--- v2.3.99-pre5/linux/drivers/net/wan/comx.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/wan/comx.c	Wed Apr 12 09:38:57 2000
@@ -91,8 +91,6 @@
 static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
 	int size, struct proc_dir_entry *dir);
 
-static void comx_fill_inode(struct inode *inode, int fill);
-
 static struct dentry_operations comx_dentry_operations = {
 	NULL,			/* revalidate */
 	NULL,			/* d_hash */
@@ -101,13 +99,7 @@
 };
 
 
-struct proc_dir_entry comx_root_dir = {
-	0, 4, "comx",
-	S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, 2, 0, 0,
-	0, &comx_root_inode_ops,
-	NULL, comx_fill_inode,
-	NULL, &proc_root, NULL 
-};
+static struct proc_dir_entry * comx_root_dir;
 
 struct comx_debugflags_struct	comx_debugflags[] = {
 	{ "comx_rx",		DEBUG_COMX_RX		},
@@ -121,14 +113,6 @@
 	{ NULL,			0			} 
 };
 
-static void comx_fill_inode(struct inode *inode, int fill)
-{
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-}
-
 
 int comx_debug(struct net_device *dev, char *fmt, ...)
 {
@@ -853,14 +837,13 @@
 	struct net_device *dev;
 	struct comx_channel *ch;
 
-	if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR;
+	if (dir->i_ino != comx_root_dir->low_ino) return -ENOTDIR;
 
 	if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR, 
-		&comx_root_dir)) == NULL) {
+		comx_root_dir)) == NULL) {
 		return -EIO;
 	}
 
-	new_dir->proc_iops = &proc_dir_inode_operations;  // ez egy normalis /proc konyvtar
 	new_dir->nlink = 2;
 	new_dir->data = NULL; // ide jon majd a struct dev
 
@@ -930,7 +913,7 @@
 	int ret;
 
 	/* Egyelore miert ne ? */
-	if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR;
+	if (dir->i_ino != comx_root_dir->low_ino) return -ENOTDIR;
 
 	if (dev->flags & IFF_UP) {
 		printk(KERN_ERR "%s: down interface before removing it\n", dev->name);
@@ -968,8 +951,7 @@
 	remove_proc_entry(FILENAME_STATUS, entry);
 	remove_proc_entry(FILENAME_HARDWARE, entry);
 	remove_proc_entry(FILENAME_PROTOCOL, entry);
-	remove_proc_entry(dentry->d_name.name, &comx_root_dir);
-//	proc_unregister(&comx_root_dir, dentry->d_inode->i_ino);
+	remove_proc_entry(dentry->d_name.name, comx_root_dir);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -1133,23 +1115,15 @@
 {
 	struct proc_dir_entry *new_file;
 
-	memcpy(&comx_root_inode_ops, &proc_dir_inode_operations, 
-		sizeof(struct inode_operations));
 	comx_root_inode_ops.lookup = &comx_lookup;
 	comx_root_inode_ops.mkdir = &comx_mkdir;
 	comx_root_inode_ops.rmdir = &comx_rmdir;
 
-	memcpy(&comx_normal_inode_ops, &proc_net_inode_operations, 
-		sizeof(struct inode_operations));
-	comx_normal_inode_ops.default_file_ops = &comx_normal_file_ops;
 	comx_normal_inode_ops.lookup = &comx_lookup;
 
 	memcpy(&comx_debug_inode_ops, &comx_normal_inode_ops, 
 		sizeof(struct inode_operations));
-	comx_debug_inode_ops.default_file_ops = &comx_debug_file_ops;
 
-	memcpy(&comx_normal_file_ops, proc_net_inode_operations.default_file_ops,
-		sizeof(struct file_operations));
 	comx_normal_file_ops.open = &comx_file_open;
 	comx_normal_file_ops.release = &comx_file_release;
 
@@ -1158,22 +1132,25 @@
 	comx_debug_file_ops.llseek = &comx_debug_lseek;
 	comx_debug_file_ops.read = &comx_debug_read;
 
-	if (proc_register(&proc_root, &comx_root_dir) < 0) return -ENOMEM;
-
+	comx_root_dir = create_proc_entry("comx", 
+		S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root);
+	if (!comx_root_dir)
+		return -ENOMEM;
+	comx_root_dir->proc_iops = &comx_root_inode_ops;
 
 	if ((new_file = create_proc_entry(FILENAME_HARDWARELIST, 
-	   S_IFREG | 0444, &comx_root_dir)) == NULL) {
+	   S_IFREG | 0444, comx_root_dir)) == NULL) {
 		return -ENOMEM;
 	}
 	
-	new_file->ops = &comx_normal_inode_ops;
+	new_file->proc_iops = &comx_normal_inode_ops;
 	new_file->data = new_file;
 	new_file->read_proc = &comx_root_read_proc;
 	new_file->write_proc = NULL;
 	new_file->nlink = 1;
 
 	if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST, 
-	   S_IFREG | 0444, &comx_root_dir)) == NULL) {
+	   S_IFREG | 0444, comx_root_dir)) == NULL) {
 		return -ENOMEM;
 	}
 	
@@ -1217,9 +1194,9 @@
 #ifdef MODULE
 void cleanup_module(void)
 {
-	remove_proc_entry(FILENAME_HARDWARELIST, &comx_root_dir);
-	remove_proc_entry(FILENAME_PROTOCOLLIST, &comx_root_dir);
-	proc_unregister(&proc_root, comx_root_dir.low_ino);
+	remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir);
+	remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir);
+	remove_proc_entry(comx_root_dir->name, &proc_root);
 }
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/comx.h linux/drivers/net/wan/comx.h
--- v2.3.99-pre5/linux/drivers/net/wan/comx.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/net/wan/comx.h	Wed Apr 12 09:38:57 2000
@@ -220,7 +220,7 @@
 #define	SEEK_END	2
 #endif
 
-extern struct proc_dir_entry comx_root_dir;
+extern struct proc_dir_entry * comx_root_dir;
 
 extern int	comx_register_hardware(struct comx_hardware *comx_hw);
 extern int	comx_unregister_hardware(char *name);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c
--- v2.3.99-pre5/linux/drivers/net/wan/cosa.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/net/wan/cosa.c	Fri Apr 21 16:37:56 2000
@@ -79,6 +79,7 @@
 
 /* ---------- Headers, macros, data structures ---------- */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
@@ -374,7 +375,7 @@
 	int i;
 
 	printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
 #endif
 	if (cosa_major > 0) {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/Makefile linux/drivers/net/wan/lmc/Makefile
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/Makefile	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,39 @@
+# File: drivers/lmc/Makefile
+#
+# Makefile for the Lan Media 21140 based WAN cards
+# Specifically the 1000,1200,5200,5245
+#
+
+ifeq ($(CONFIG_LANMEDIA),y)
+    O_TARGET := lmc.o
+    O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
+else
+  ifeq ($(CONFIG_LANMEDIA),m)
+    MOD_LIST_NAME := NET_MODULES
+    M_OBJS := lmc.o
+    O_TARGET := lmc.o
+    O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
+  endif
+endif
+
+#
+# Base debugging and event log (doubles lmc.o size)
+#
+# DBGDEF =  \
+# -DDEBUG
+
+#
+# Like above except every packet gets echoed to KERN_DEBUG
+# in hex
+#
+# DBDEF = \
+# -DDEBUG \
+# -DLMC_PACKET_LOG
+
+EXTRA_CFLAGS += -I. $(DBGDEF)
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
+
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc.h linux/drivers/net/wan/lmc/lmc.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,32 @@
+#ifndef _LMC_H_
+#define _LMC_H_
+
+#include "lmc_var.h"
+
+/*
+ * prototypes for everyone
+ */
+int lmc_probe(struct net_device * dev);
+unsigned lmc_mii_readreg(lmc_softc_t * const sc, unsigned
+      			  devaddr, unsigned regno);
+void lmc_mii_writereg(lmc_softc_t * const sc, unsigned devaddr,
+			       unsigned regno, unsigned data);
+void lmc_led_on(lmc_softc_t * const, u_int32_t);
+void lmc_led_off(lmc_softc_t * const, u_int32_t);
+unsigned lmc_mii_readreg(lmc_softc_t * const, unsigned, unsigned);
+void lmc_mii_writereg(lmc_softc_t * const, unsigned, unsigned, unsigned);
+void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits);
+void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits);
+
+int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+extern lmc_media_t lmc_ds3_media;
+extern lmc_media_t lmc_ssi_media;
+extern lmc_media_t lmc_t1_media;
+extern lmc_media_t lmc_hssi_media;
+
+#ifdef _DBG_EVENTLOG
+static void lmcEventLog( u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3 );
+#endif
+
+#endif
\ No newline at end of file
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.c linux/drivers/net/wan/lmc/lmc_debug.c
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_debug.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,87 @@
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include "lmc_ver.h"
+#include "lmc_debug.h"
+
+/*
+ * Prints out len, max to 80 octets using printk, 20 per line
+ */
+void lmcConsoleLog(char *type, unsigned char *ucData, int iLen)
+{
+#ifdef DEBUG
+#ifdef LMC_PACKET_LOG
+  int iNewLine = 1;
+  char str[80], *pstr;
+  
+  sprintf(str, KERN_DEBUG "lmc: %s: ", type);
+  pstr = str+strlen(str);
+  
+  if(iLen > 240){
+      printk(KERN_DEBUG "lmc: Printing 240 chars... out of: %d\n", iLen);
+    iLen = 240;
+  }
+  else{
+      printk(KERN_DEBUG "lmc: Printing %d chars\n", iLen);
+  }
+
+  while(iLen > 0) 
+    {
+      sprintf(pstr, "%02x ", *ucData);
+      pstr+=3;
+      ucData++;
+      if( !(iNewLine % 20))
+	{
+	  sprintf(pstr, "\n");
+	  printk(str);
+	  sprintf(str, KERN_DEBUG "lmc: %s: ", type);
+	  pstr=str+strlen(str);
+	}
+      iNewLine++;
+      iLen--;
+    }
+  sprintf(pstr, "\n");
+  printk(str);
+#endif
+#endif
+}
+
+#ifdef DEBUG
+u_int32_t lmcEventLogIndex = 0;
+u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
+#endif
+
+void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3)
+{
+#ifdef DEBUG
+  lmcEventLogBuf[lmcEventLogIndex++] = EventNum;
+  lmcEventLogBuf[lmcEventLogIndex++] = arg2;
+  lmcEventLogBuf[lmcEventLogIndex++] = arg3;
+  lmcEventLogBuf[lmcEventLogIndex++] = jiffies;
+
+  lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1;
+#endif
+}
+
+inline void lmc_trace(struct net_device *dev, char *msg){
+#ifdef LMC_TRACE
+    unsigned long j = jiffies + 3; /* Wait for 50 ms */
+
+    if(in_interrupt()){
+        printk("%s: * %s\n", dev->name, msg);
+//        while(jiffies < j+10)
+//            ;
+    }
+    else {
+        printk("%s: %s\n", dev->name, msg);
+        while(jiffies < j)
+            schedule();
+    }
+#endif
+}
+
+
+/* --------------------------- end if_lmc_linux.c ------------------------ */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.h linux/drivers/net/wan/lmc/lmc_debug.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_debug.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,52 @@
+#ifndef _LMC_DEBUG_H_
+#define _LMC_DEBUG_H_
+
+#ifdef DEBUG
+#ifdef LMC_PACKET_LOG
+#define LMC_CONSOLE_LOG(x,y,z) lmcConsoleLog((x), (y), (z))
+#else
+#define LMC_CONSOLE_LOG(x,y,z)
+#endif
+#else
+#define LMC_CONSOLE_LOG(x,y,z)
+#endif
+
+
+
+/* Debug --- Event log definitions --- */
+/* EVENTLOGSIZE*EVENTLOGARGS needs to be a power of 2 */
+#define LMC_EVENTLOGSIZE 1024	/* number of events in eventlog */
+#define LMC_EVENTLOGARGS 4		/* number of args for each event */
+
+/* event indicators */
+#define LMC_EVENT_XMT           1
+#define LMC_EVENT_XMTEND        2
+#define LMC_EVENT_XMTINT        3
+#define LMC_EVENT_RCVINT        4
+#define LMC_EVENT_RCVEND        5
+#define LMC_EVENT_INT           6
+#define LMC_EVENT_XMTINTTMO     7
+#define LMC_EVENT_XMTPRCTMO     8
+#define LMC_EVENT_INTEND        9
+#define LMC_EVENT_RESET1       10
+#define LMC_EVENT_RESET2       11
+#define LMC_EVENT_FORCEDRESET  12
+#define LMC_EVENT_WATCHDOG     13
+#define LMC_EVENT_BADPKTSURGE  14
+#define LMC_EVENT_TBUSY0       15
+#define LMC_EVENT_TBUSY1       16
+
+
+#ifdef DEBUG
+extern u_int32_t lmcEventLogIndex;
+extern u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
+#define LMC_EVENT_LOG(x, y, z) lmcEventLog((x), (y), (z))
+#else
+#define LMC_EVENT_LOG(x,y,z)
+#endif /* end ifdef _DBG_EVENTLOG */
+
+void lmcConsoleLog(char *type, unsigned char *ucData, int iLen);
+void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3);
+inline void lmc_trace(struct net_device *dev, char *msg);
+
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ioctl.h linux/drivers/net/wan/lmc/lmc_ioctl.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ioctl.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_ioctl.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,257 @@
+#ifndef _LMC_IOCTL_H_
+#define _LMC_IOCTL_H_
+/*	$Id: lmc_ioctl.h,v 1.15 2000/04/06 12:16:43 asj Exp $	*/
+
+ /*
+  * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+  * All rights reserved.  www.lanmedia.com
+  *
+  * This code is written by:
+  * Andrew Stanley-Jones (asj@cban.com)
+  * Rob Braun (bbraun@vix.com),
+  * Michael Graff (explorer@vix.com) and
+  * Matt Thomas (matt@3am-software.com).
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU Public License version 2, incorporated herein by reference.
+  */
+
+#define LMCIOCGINFO             SIOCDEVPRIVATE+3 /* get current state */
+#define LMCIOCSINFO             SIOCDEVPRIVATE+4 /* set state to user values */
+#define LMCIOCGETLMCSTATS       SIOCDEVPRIVATE+5
+#define LMCIOCCLEARLMCSTATS     SIOCDEVPRIVATE+6
+#define LMCIOCDUMPEVENTLOG      SIOCDEVPRIVATE+7
+#define LMCIOCGETXINFO          SIOCDEVPRIVATE+8
+#define LMCIOCSETCIRCUIT        SIOCDEVPRIVATE+9
+#define LMCIOCUNUSEDATM         SIOCDEVPRIVATE+10
+#define LMCIOCRESET             SIOCDEVPRIVATE+11
+#define LMCIOCT1CONTROL         SIOCDEVPRIVATE+12
+#define LMCIOCIFTYPE            SIOCDEVPRIVATE+13
+#define LMCIOCXILINX            SIOCDEVPRIVATE+14
+
+#define LMC_CARDTYPE_UNKNOWN            -1
+#define LMC_CARDTYPE_HSSI               1       /* probed card is a HSSI card */
+#define LMC_CARDTYPE_DS3                2       /* probed card is a DS3 card */
+#define LMC_CARDTYPE_SSI                3       /* probed card is a SSI card */
+#define LMC_CARDTYPE_T1                 4       /* probed card is a T1 card */
+
+#define LMC_CTL_CARDTYPE_LMC5200	0	/* HSSI */
+#define LMC_CTL_CARDTYPE_LMC5245	1	/* DS3 */
+#define LMC_CTL_CARDTYPE_LMC1000	2	/* SSI, V.35 */
+#define LMC_CTL_CARDTYPE_LMC1200        3       /* DS1 */
+
+#define LMC_CTL_OFF			0	/* generic OFF value */
+#define LMC_CTL_ON			1	/* generic ON value */
+
+#define LMC_CTL_CLOCK_SOURCE_EXT	0	/* clock off line */
+#define LMC_CTL_CLOCK_SOURCE_INT	1	/* internal clock */
+
+#define LMC_CTL_CRC_LENGTH_16		16
+#define LMC_CTL_CRC_LENGTH_32		32
+#define LMC_CTL_CRC_BYTESIZE_2          2
+#define LMC_CTL_CRC_BYTESIZE_4          4
+
+
+#define LMC_CTL_CABLE_LENGTH_LT_100FT	0	/* DS3 cable < 100 feet */
+#define LMC_CTL_CABLE_LENGTH_GT_100FT	1	/* DS3 cable >= 100 feet */
+
+#define LMC_CTL_CIRCUIT_TYPE_E1 0
+#define LMC_CTL_CIRCUIT_TYPE_T1 1
+
+/*
+ * IFTYPE defines
+ */
+#define LMC_PPP         1               /* use sppp interface */
+#define LMC_NET         2               /* use direct net interface */
+#define LMC_RAW         3               /* use direct net interface */
+
+/*
+ * These are not in the least IOCTL related, but I want them common.
+ */
+/*
+ * assignments for the GPIO register on the DEC chip (common)
+ */
+#define LMC_GEP_INIT		0x01 /* 0: */
+#define LMC_GEP_RESET		0x02 /* 1: */
+#define LMC_GEP_MODE		0x10 /* 4: */
+#define LMC_GEP_DP		0x20 /* 5: */
+#define LMC_GEP_DATA		0x40 /* 6: serial out */
+#define LMC_GEP_CLK	        0x80 /* 7: serial clock */
+
+/*
+ * HSSI GPIO assignments
+ */
+#define LMC_GEP_HSSI_ST		0x04 /* 2: receive timing sense (deprecated) */
+#define LMC_GEP_HSSI_CLOCK	0x08 /* 3: clock source */
+
+/*
+ * T1 GPIO assignments
+ */
+#define LMC_GEP_SSI_GENERATOR	0x04 /* 2: enable prog freq gen serial i/f */
+#define LMC_GEP_SSI_TXCLOCK	0x08 /* 3: provide clock on TXCLOCK output */
+
+/*
+ * Common MII16 bits
+ */
+#define LMC_MII16_LED0         0x0080
+#define LMC_MII16_LED1         0x0100
+#define LMC_MII16_LED2         0x0200
+#define LMC_MII16_LED3         0x0400  /* Error, and the red one */
+#define LMC_MII16_LED_ALL      0x0780  /* LED bit mask */
+#define LMC_MII16_FIFO_RESET   0x0800
+
+/*
+ * definitions for HSSI
+ */
+#define LMC_MII16_HSSI_TA      0x0001
+#define LMC_MII16_HSSI_CA      0x0002
+#define LMC_MII16_HSSI_LA      0x0004
+#define LMC_MII16_HSSI_LB      0x0008
+#define LMC_MII16_HSSI_LC      0x0010
+#define LMC_MII16_HSSI_TM      0x0020
+#define LMC_MII16_HSSI_CRC     0x0040
+
+/*
+ * assignments for the MII register 16 (DS3)
+ */
+#define LMC_MII16_DS3_ZERO	0x0001
+#define LMC_MII16_DS3_TRLBK	0x0002
+#define LMC_MII16_DS3_LNLBK	0x0004
+#define LMC_MII16_DS3_RAIS	0x0008
+#define LMC_MII16_DS3_TAIS	0x0010
+#define LMC_MII16_DS3_BIST	0x0020
+#define LMC_MII16_DS3_DLOS	0x0040
+#define LMC_MII16_DS3_CRC	0x1000
+#define LMC_MII16_DS3_SCRAM	0x2000
+#define LMC_MII16_DS3_SCRAM_LARS 0x4000
+
+/* Note: 2 pairs of LEDs where swapped by mistake
+ * in Xilinx code for DS3 & DS1 adapters */
+#define LMC_DS3_LED0    0x0100          /* bit 08  yellow */
+#define LMC_DS3_LED1    0x0080          /* bit 07  blue   */
+#define LMC_DS3_LED2    0x0400          /* bit 10  green  */
+#define LMC_DS3_LED3    0x0200          /* bit 09  red    */
+
+/*
+ * framer register 0 and 7 (7 is latched and reset on read)
+ */
+#define LMC_FRAMER_REG0_DLOS            0x80    /* digital loss of service */
+#define LMC_FRAMER_REG0_OOFS            0x40    /* out of frame sync */
+#define LMC_FRAMER_REG0_AIS             0x20    /* alarm indication signal */
+#define LMC_FRAMER_REG0_CIS             0x10    /* channel idle */
+#define LMC_FRAMER_REG0_LOC             0x08    /* loss of clock */
+
+/*
+ * Framer register 9 contains the blue alarm signal
+ */
+#define LMC_FRAMER_REG9_RBLUE          0x02     /* Blue alarm failure */
+
+/*
+ * Framer register 0x10 contains xbit error
+ */
+#define LMC_FRAMER_REG10_XBIT          0x01     /* X bit error alarm failure */
+
+/*
+ * And SSI, LMC1000
+ */
+#define LMC_MII16_SSI_DTR	0x0001	/* DTR output RW */
+#define LMC_MII16_SSI_DSR	0x0002	/* DSR input RO */
+#define LMC_MII16_SSI_RTS	0x0004	/* RTS output RW */
+#define LMC_MII16_SSI_CTS	0x0008	/* CTS input RO */
+#define LMC_MII16_SSI_DCD	0x0010	/* DCD input RO */
+#define LMC_MII16_SSI_RI		0x0020	/* RI input RO */
+#define LMC_MII16_SSI_CRC                0x1000  /* CRC select - RW */
+
+/*
+ * bits 0x0080 through 0x0800 are generic, and described
+ * above with LMC_MII16_LED[0123] _LED_ALL, and _FIFO_RESET
+ */
+#define LMC_MII16_SSI_LL		0x1000	/* LL output RW */
+#define LMC_MII16_SSI_RL		0x2000	/* RL output RW */
+#define LMC_MII16_SSI_TM		0x4000	/* TM input RO */
+#define LMC_MII16_SSI_LOOP	0x8000	/* loopback enable RW */
+
+/*
+ * Some of the MII16 bits are mirrored in the MII17 register as well,
+ * but let's keep thing seperate for now, and get only the cable from
+ * the MII17.
+ */
+#define LMC_MII17_SSI_CABLE_MASK	0x0038	/* mask to extract the cable type */
+#define LMC_MII17_SSI_CABLE_SHIFT 3	/* shift to extract the cable type */
+
+/*
+ * And T1, LMC1200
+ */
+#define LMC_MII16_T1_UNUSED1    0x0003
+#define LMC_MII16_T1_XOE                0x0004
+#define LMC_MII16_T1_RST                0x0008  /* T1 chip reset - RW */
+#define LMC_MII16_T1_Z                  0x0010  /* output impedance T1=1, E1=0 output - RW */
+#define LMC_MII16_T1_INTR               0x0020  /* interrupt from 8370 - RO */
+#define LMC_MII16_T1_ONESEC             0x0040  /* one second square wave - ro */
+
+#define LMC_MII16_T1_LED0               0x0100
+#define LMC_MII16_T1_LED1               0x0080
+#define LMC_MII16_T1_LED2               0x0400
+#define LMC_MII16_T1_LED3               0x0200
+#define LMC_MII16_T1_FIFO_RESET 0x0800
+
+#define LMC_MII16_T1_CRC                0x1000  /* CRC select - RW */
+#define LMC_MII16_T1_UNUSED2    0xe000
+
+
+/* 8370 framer registers  */
+
+#define T1FRAMER_ALARM1_STATUS  0x47
+#define T1FRAMER_ALARM2_STATUS  0x48
+#define T1FRAMER_FERR_LSB               0x50
+#define T1FRAMER_FERR_MSB               0x51    /* framing bit error counter */
+#define T1FRAMER_LCV_LSB                0x54
+#define T1FRAMER_LCV_MSB                0x55    /* line code violation counter */
+#define T1FRAMER_AERR                   0x5A
+
+/* mask for the above AERR register */
+#define T1FRAMER_LOF_MASK               (0x0f0) /* receive loss of frame */
+#define T1FRAMER_COFA_MASK              (0x0c0) /* change of frame alignment */
+#define T1FRAMER_SEF_MASK               (0x03)  /* severely errored frame  */
+
+/* 8370 framer register ALM1 (0x47) values
+ * used to determine link status
+ */
+
+#define T1F_SIGFRZ      0x01    /* signaling freeze */
+#define T1F_RLOF        0x02    /* receive loss of frame alignment */
+#define T1F_RLOS        0x04    /* receive loss of signal */
+#define T1F_RALOS       0x08    /* receive analog loss of signal or RCKI loss of clock */
+#define T1F_RAIS        0x10    /* receive alarm indication signal */
+#define T1F_UNUSED      0x20
+#define T1F_RYEL        0x40    /* receive yellow alarm */
+#define T1F_RMYEL       0x80    /* receive multiframe yellow alarm */
+
+#define LMC_T1F_WRITE       0
+#define LMC_T1F_READ        1
+
+typedef struct lmc_st1f_control {
+  int command;
+  int address;
+  int value;
+  char *data;
+} lmc_t1f_control;
+
+enum lmc_xilinx_c {
+    lmc_xilinx_reset = 1,
+    lmc_xilinx_load_prom = 2,
+    lmc_xilinx_load = 3
+};
+
+struct lmc_xilinx_control {
+    enum lmc_xilinx_c command;
+    int len;
+    char *data;
+};
+
+/* ------------------ end T1 defs ------------------- */
+
+#define LMC_MII_LedMask                 0x0780
+#define LMC_MII_LedBitPos               7
+
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_main.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_main.c	Tue Apr 25 17:52:01 2000
@@ -0,0 +1,2486 @@
+ /*
+  * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+  * All rights reserved.  www.lanmedia.com
+  *
+  * This code is written by:
+  * Andrew Stanley-Jones (asj@cban.com)
+  * Rob Braun (bbraun@vix.com),
+  * Michael Graff (explorer@vix.com) and
+  * Matt Thomas (matt@3am-software.com).
+  *
+  * With Help By:
+  * David Boggs
+  * Ron Crane
+  * Allan Cox
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU Public License version 2, incorporated herein by reference.
+  *
+  * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+  *
+  * To control link specific options lmcctl is required.
+  * It can be obtained from ftp.lanmedia.com.
+  *
+  * Linux driver notes:
+  * Linux uses the device struct lmc_private to pass private information
+  * arround.
+  *
+  * The initialization portion of this driver (the lmc_reset() and the
+  * lmc_dec_reset() functions, as well as the led controls and the
+  * lmc_initcsrs() functions.
+  *
+  * The watchdog function runs every second and checks to see if
+  * we still have link, and that the timing source is what we expected
+  * it to be.  If link is lost, the interface is marked down, and
+  * we no longer can transmit.
+  *
+  */
+
+/* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/segment.h>
+#include <linux/init.h>
+
+#if LINUX_VERSION_CODE < 0x20155
+#include <linux/bios32.h>
+#endif
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h>             /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+
+#if LINUX_VERSION_CODE >= 0x20200
+#include <asm/uaccess.h>
+//#include <asm/spinlock.h>
+#else				/* 2.0 kernel */
+#define ARPHRD_HDLC 513
+#endif
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define DRIVER_MAJOR_VERSION     1
+#define DRIVER_MINOR_VERSION    34
+#define DRIVER_SUB_VERSION       0
+
+#define DRIVER_VERSION  ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION)
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_ioctl.h"
+#include "lmc_debug.h"
+#include "lmc_proto.h"
+
+
+static int Lmc_Count = 0;
+static struct net_device *Lmc_root_dev = NULL;
+static u8 cards_found = 0;
+
+static int lmc_first_load = 0;
+
+int LMC_PKT_BUF_SZ = 1542;
+
+#ifdef MODULE
+static struct pci_device_id lmc_pci_tbl[] __devinitdata = {
+    { 0x1011, 0x009, 0x1379, PCI_ANY_ID, 0, 0, 0},
+    { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, lmc_pci_tbl);
+#endif
+
+
+int lmc_probe_fake(struct net_device *dev);
+static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq,
+				 int chip_id, int subdevice, int board_idx);
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_rx (struct net_device *dev);
+static int lmc_open(struct net_device *dev);
+static int lmc_close(struct net_device *dev);
+static struct enet_statistics *lmc_get_stats(struct net_device *dev);
+static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int lmc_set_config(struct net_device *dev, struct ifmap *map);
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
+static void lmc_softreset(lmc_softc_t * const);
+static void lmc_running_reset(struct net_device *dev);
+static int lmc_ifdown(struct net_device * const);
+static void lmc_watchdog(unsigned long data);
+static int lmc_init(struct net_device * const);
+static void lmc_reset(lmc_softc_t * const sc);
+static void lmc_dec_reset(lmc_softc_t * const sc);
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev);
+int lmc_setup(void);
+#endif
+
+
+/*
+ * linux reserves 16 device specific IOCTLs.  We call them
+ * LMCIOC* to control various bits of our world.
+ */
+int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
+{
+    lmc_softc_t *sc;
+    lmc_ctl_t ctl;
+    int ret;
+    u_int16_t regVal;
+    unsigned long flags;
+
+    struct sppp *sp;
+
+    ret = -EOPNOTSUPP;
+
+    sc = dev->priv;
+
+    lmc_trace(dev, "lmc_ioctl in");
+
+    /*
+     * Most functions mess with the structure
+     * Disable interupts while we do the polling
+     */
+    spin_lock_irqsave(&sc->lmc_lock, flags);
+
+    switch (cmd) {
+        /*
+         * Return current driver state.  Since we keep this up
+         * To date internally, just copy this out to the user.
+         */
+    case LMCIOCGINFO: /*fold01*/
+        LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t));
+        ret = 0;
+        break;
+
+    case LMCIOCSINFO: /*fold01*/
+        sp = &((struct ppp_device *) dev)->sppp;
+        if (!suser ()) {
+            ret = -EPERM;
+            break;
+        }
+
+        if(dev->flags & IFF_UP){
+            ret = -EBUSY;
+            break;
+        }
+
+        LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t));
+
+        sc->lmc_media->set_status (sc, &ctl);
+
+        if(ctl.crc_length != sc->ictl.crc_length) {
+            sc->lmc_media->set_crc_length(sc, ctl.crc_length);
+	    if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16)
+		sc->TxDescriptControlInit |=  LMC_TDES_ADD_CRC_DISABLE;
+	    else
+		sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE;
+        }
+
+        if (ctl.keepalive_onoff == LMC_CTL_OFF)
+            sp->pp_flags &= ~PP_KEEPALIVE;	/* Turn off */
+        else
+            sp->pp_flags |= PP_KEEPALIVE;	/* Turn on */
+
+        ret = 0;
+        break;
+
+    case LMCIOCIFTYPE: /*fold01*/
+        {
+            u_int16_t	old_type = sc->if_type;
+            u_int16_t	new_type;
+
+	    if (!suser ()) {
+		ret = -EPERM;
+		break;
+	    }
+
+	    LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t));
+
+            
+	    if (new_type == old_type)
+	    {
+		ret = 0 ;
+		break;				/* no change */
+            }
+            
+            lmc_proto_close(sc);
+            lmc_proto_detach(sc);
+
+            sc->if_type = new_type;
+//            lmc_proto_init(sc);
+            lmc_proto_attach(sc);
+            lmc_proto_open(sc);
+
+	    ret = 0 ;
+	    break ;
+	}
+
+    case LMCIOCGETXINFO: /*fold01*/
+        sc->lmc_xinfo.Magic0 = 0xBEEFCAFE;
+
+        sc->lmc_xinfo.PciCardType = sc->lmc_cardtype;
+        sc->lmc_xinfo.PciSlotNumber = 0;
+        sc->lmc_xinfo.DriverMajorVersion = DRIVER_MAJOR_VERSION;
+        sc->lmc_xinfo.DriverMinorVersion = DRIVER_MINOR_VERSION;
+        sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION;
+        sc->lmc_xinfo.XilinxRevisionNumber =
+            lmc_mii_readreg (sc, 0, 3) & 0xf;
+        sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ;
+        sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc);
+        sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16);
+
+        sc->lmc_xinfo.Magic1 = 0xDEADBEEF;
+
+        LMC_COPY_TO_USER(ifr->ifr_data, &sc->lmc_xinfo,
+                         sizeof (struct lmc_xinfo));
+        ret = 0;
+
+        break;
+
+    case LMCIOCGETLMCSTATS: /*fold01*/
+        if (sc->lmc_cardtype == LMC_CARDTYPE_T1){
+            lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB);
+            sc->stats.framingBitErrorCount +=
+                lmc_mii_readreg (sc, 0, 18) & 0xff;
+            lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_MSB);
+            sc->stats.framingBitErrorCount +=
+                (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8;
+            lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_LSB);
+            sc->stats.lineCodeViolationCount +=
+                lmc_mii_readreg (sc, 0, 18) & 0xff;
+            lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_MSB);
+            sc->stats.lineCodeViolationCount +=
+                (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8;
+            lmc_mii_writereg (sc, 0, 17, T1FRAMER_AERR);
+            regVal = lmc_mii_readreg (sc, 0, 18) & 0xff;
+
+            sc->stats.lossOfFrameCount +=
+                (regVal & T1FRAMER_LOF_MASK) >> 4;
+            sc->stats.changeOfFrameAlignmentCount +=
+                (regVal & T1FRAMER_COFA_MASK) >> 2;
+            sc->stats.severelyErroredFrameCount +=
+                regVal & T1FRAMER_SEF_MASK;
+        }
+
+        LMC_COPY_TO_USER(ifr->ifr_data, &sc->stats,
+                         sizeof (struct lmc_statistics));
+
+        ret = 0;
+        break;
+
+    case LMCIOCCLEARLMCSTATS: /*fold01*/
+        if (!suser ()){
+            ret = -EPERM;
+            break;
+        }
+
+        memset (&sc->stats, 0, sizeof (struct lmc_statistics));
+        sc->stats.check = STATCHECK;
+        sc->stats.version_size = (DRIVER_VERSION << 16) +
+            sizeof (struct lmc_statistics);
+        sc->stats.lmc_cardtype = sc->lmc_cardtype;
+        ret = 0;
+        break;
+
+    case LMCIOCSETCIRCUIT: /*fold01*/
+        if (!suser ()){
+            ret = -EPERM;
+            break;
+        }
+
+        if(dev->flags & IFF_UP){
+            ret = -EBUSY;
+            break;
+        }
+
+        LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t));
+        sc->lmc_media->set_circuit_type(sc, ctl.circuit_type);
+        sc->ictl.circuit_type = ctl.circuit_type;
+        ret = 0;
+
+        break;
+
+    case LMCIOCRESET: /*fold01*/
+        if (!suser ()){
+            ret = -EPERM;
+            break;
+        }
+
+        /* Reset driver and bring back to current state */
+        printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
+        lmc_running_reset (dev);
+        printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
+
+        LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
+
+        ret = 0;
+        break;
+
+#ifdef DEBUG
+    case LMCIOCDUMPEVENTLOG:
+        LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32));
+        LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf));
+
+        ret = 0;
+        break;
+#endif /* end ifdef _DBG_EVENTLOG */
+    case LMCIOCT1CONTROL: /*fold01*/
+        if (sc->lmc_cardtype != LMC_CARDTYPE_T1){
+            ret = -EOPNOTSUPP;
+            break;
+        }
+        break;
+    case LMCIOCXILINX: /*fold01*/
+        {
+            struct lmc_xilinx_control xc; /*fold02*/
+
+            if (!suser ()){
+                ret = -EPERM;
+                break;
+            }
+
+            /*
+             * Stop the xwitter whlie we restart the hardware
+             */
+            LMC_XMITTER_BUSY(dev);
+
+            LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control));
+            switch(xc.command){
+            case lmc_xilinx_reset: /*fold02*/
+                {
+                    u16 mii;
+                    mii = lmc_mii_readreg (sc, 0, 16);
+
+                    /*
+                     * Make all of them 0 and make input
+                     */
+                    lmc_gpio_mkinput(sc, 0xff);
+
+                    /*
+                     * make the reset output
+                     */
+                    lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
+
+                    /*
+                     * RESET low to force configuration.  This also forces
+                     * the transmitter clock to be internal, but we expect to reset
+                     * that later anyway.
+                     */
+
+                    sc->lmc_gpio &= ~LMC_GEP_RESET;
+                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+                    /*
+                     * hold for more than 10 microseconds
+                     */
+                    udelay(50);
+
+                    sc->lmc_gpio |= LMC_GEP_RESET;
+                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+                    /*
+                     * stop driving Xilinx-related signals
+                     */
+                    lmc_gpio_mkinput(sc, 0xff);
+
+                    /* Reset the frammer hardware */
+                    sc->lmc_media->set_link_status (sc, 1);
+                    sc->lmc_media->set_status (sc, NULL);
+//                    lmc_softreset(sc);
+
+                    {
+                        int i;
+                        for(i = 0; i < 5; i++){
+                            lmc_led_on(sc, LMC_DS3_LED0);
+                            mdelay(100);
+                            lmc_led_off(sc, LMC_DS3_LED0);
+                            lmc_led_on(sc, LMC_DS3_LED1);
+                            mdelay(100);
+                            lmc_led_off(sc, LMC_DS3_LED1);
+                            lmc_led_on(sc, LMC_DS3_LED3);
+                            mdelay(100);
+                            lmc_led_off(sc, LMC_DS3_LED3);
+                            lmc_led_on(sc, LMC_DS3_LED2);
+                            mdelay(100);
+                            lmc_led_off(sc, LMC_DS3_LED2);
+                        }
+                    }
+                    
+                    
+
+                    ret = 0x0;
+
+                }
+
+                break;
+            case lmc_xilinx_load_prom: /*fold02*/
+                {
+                    u16 mii;
+                    int timeout = 500000;
+                    mii = lmc_mii_readreg (sc, 0, 16);
+
+                    /*
+                     * Make all of them 0 and make input
+                     */
+                    lmc_gpio_mkinput(sc, 0xff);
+
+                    /*
+                     * make the reset output
+                     */
+                    lmc_gpio_mkoutput(sc,  LMC_GEP_DP | LMC_GEP_RESET);
+
+                    /*
+                     * RESET low to force configuration.  This also forces
+                     * the transmitter clock to be internal, but we expect to reset
+                     * that later anyway.
+                     */
+
+                    sc->lmc_gpio &= ~(LMC_GEP_RESET | LMC_GEP_DP);
+                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+                    /*
+                     * hold for more than 10 microseconds
+                     */
+                    udelay(50);
+
+                    sc->lmc_gpio |= LMC_GEP_DP | LMC_GEP_RESET;
+                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+                    /*
+                     * busy wait for the chip to reset
+                     */
+                    while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
+                           (timeout-- > 0))
+                        ;
+
+
+                    /*
+                     * stop driving Xilinx-related signals
+                     */
+                    lmc_gpio_mkinput(sc, 0xff);
+
+                    ret = 0x0;
+                    
+
+                    break;
+
+                }
+
+            case lmc_xilinx_load: /*fold02*/
+                {
+                    char *data;
+                    int pos;
+                    int timeout = 500000;
+
+                    if(xc.data == 0x0){
+                            ret = -EINVAL;
+                            break;
+                    }
+
+                    data = kmalloc(xc.len, GFP_KERNEL);
+                    if(data == 0x0){
+                            printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name);
+                            ret = -ENOMEM;
+                            break;
+                    }
+                    
+                    LMC_COPY_FROM_USER(data, xc.data, xc.len);
+
+                    printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);
+
+                    lmc_gpio_mkinput(sc, 0xff);
+
+                    /*
+                     * Clear the Xilinx and start prgramming from the DEC
+                     */
+
+                    /*
+                     * Set ouput as:
+                     * Reset: 0 (active)
+                     * DP:    0 (active)
+                     * Mode:  1
+                     *
+                     */
+                    sc->lmc_gpio = 0x00;
+                    sc->lmc_gpio &= ~LMC_GEP_DP;
+                    sc->lmc_gpio &= ~LMC_GEP_RESET;
+                    sc->lmc_gpio |=  LMC_GEP_MODE;
+                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+                    lmc_gpio_mkoutput(sc, LMC_GEP_MODE | LMC_GEP_DP | LMC_GEP_RESET);
+
+                    /*
+                     * Wait at least 10 us 20 to be safe
+                     */
+                    udelay(50);
+
+                    /*
+                     * Clear reset and activate programing lines
+                     * Reset: Input
+                     * DP:    Input
+                     * Clock: Output
+                     * Data:  Output
+                     * Mode:  Output
+                     */
+                    lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+
+                    /*
+                     * Set LOAD, DATA, Clock to 1
+                     */
+                    sc->lmc_gpio = 0x00;
+                    sc->lmc_gpio |= LMC_GEP_MODE;
+                    sc->lmc_gpio |= LMC_GEP_DATA;
+                    sc->lmc_gpio |= LMC_GEP_CLK;
+                    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+                    
+                    lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE );
+
+                    /*
+                     * busy wait for the chip to reset
+                     */
+                    while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
+                           (timeout-- > 0))
+                        ;
+
+                    printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout);
+
+                    for(pos = 0; pos < xc.len; pos++){
+                        switch(data[pos]){
+                        case 0:
+                            sc->lmc_gpio &= ~LMC_GEP_DATA; /* Data is 0 */
+                            break;
+                        case 1:
+                            sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */
+                            break;
+                        default:
+                            printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]);
+                            sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */
+                        }
+                        sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */
+                        sc->lmc_gpio |= LMC_GEP_MODE;
+                        LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+                        udelay(1);
+                        
+                        sc->lmc_gpio |= LMC_GEP_CLK; /* Put the clack back to one */
+                        sc->lmc_gpio |= LMC_GEP_MODE;
+                        LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+                        udelay(1);
+                    }
+                    if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){
+                        printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name);
+                    }
+                    else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){
+                        printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name);
+                    }
+                    else {
+                        printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos);
+                    }
+
+                    lmc_gpio_mkinput(sc, 0xff);
+                    
+                    sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
+                    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+                    sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
+                    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+                    kfree(data);
+                    
+                    ret = 0;
+                    
+                    break;
+                }
+            default: /*fold02*/
+                ret = -EBADE;
+                break;
+            }
+
+            LMC_XMITTER_FREE(dev);
+            sc->lmc_txfull = 0;
+
+        }
+        break;
+    default: /*fold01*/
+        /* If we don't know what to do, give the protocol a shot. */
+        ret = lmc_proto_ioctl (sc, ifr, cmd);
+        break;
+    }
+
+    spin_unlock_irqrestore(&sc->lmc_lock, flags); /*fold01*/
+
+    lmc_trace(dev, "lmc_ioctl out");
+
+    return ret;
+}
+
+
+/* the watchdog process that cruises around */
+static void lmc_watchdog (unsigned long data) /*fold00*/
+{
+    struct net_device *dev = (struct net_device *) data;
+    lmc_softc_t *sc;
+    int link_status;
+    u_int32_t ticks;
+    LMC_SPIN_FLAGS;
+
+    sc = dev->priv;
+
+    lmc_trace(dev, "lmc_watchdog in");
+
+    spin_lock_irqsave(&sc->lmc_lock, flags);
+
+    if(sc->check != 0xBEAFCAFE){
+        printk("LMC: Corrupt net_device stuct, breaking out\n");
+        return;
+    }
+
+
+    /* Make sure the tx jabber and rx watchdog are off,
+     * and the transmit and recieve processes are running.
+     */
+
+    LMC_CSR_WRITE (sc, csr_15, 0x00000011);
+    sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN;
+    LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+    if (sc->lmc_ok == 0)
+        goto kick_timer;
+
+    LMC_EVENT_LOG(LMC_EVENT_WATCHDOG, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
+
+    /* --- begin time out check -----------------------------------
+     * check for a transmit interrupt timeout
+     * Has the packet xmt vs xmt serviced threshold been exceeded */
+    if (sc->lmc_taint_tx == sc->lastlmc_taint_tx &&
+        sc->stats.tx_packets > sc->lasttx_packets &&
+        sc->tx_TimeoutInd == 0)
+    {
+
+        /* wait for the watchdog to come around again */
+        sc->tx_TimeoutInd = 1;
+    }
+    else if (sc->lmc_taint_tx == sc->lastlmc_taint_tx &&
+             sc->stats.tx_packets > sc->lasttx_packets &&
+             sc->tx_TimeoutInd)
+    {
+
+        LMC_EVENT_LOG(LMC_EVENT_XMTINTTMO, LMC_CSR_READ (sc, csr_status), 0);
+
+        sc->tx_TimeoutDisplay = 1;
+        sc->stats.tx_TimeoutCnt++;
+
+        /* DEC chip is stuck, hit it with a RESET!!!! */
+        lmc_running_reset (dev);
+
+
+        /* look at receive & transmit process state to make sure they are running */
+        LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+
+        /* look at: DSR - 02  for Reg 16
+         *                  CTS - 08
+         *                  DCD - 10
+         *                  RI  - 20
+         * for Reg 17
+         */
+        LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17));
+
+        /* reset the transmit timeout detection flag */
+        sc->tx_TimeoutInd = 0;
+        sc->lastlmc_taint_tx = sc->lmc_taint_tx;
+        sc->lasttx_packets = sc->stats.tx_packets;
+    }
+    else
+    {
+        sc->tx_TimeoutInd = 0;
+        sc->lastlmc_taint_tx = sc->lmc_taint_tx;
+        sc->lasttx_packets = sc->stats.tx_packets;
+    }
+
+    /* --- end time out check ----------------------------------- */
+
+
+    link_status = sc->lmc_media->get_link_status (sc);
+
+    /*
+     * hardware level link lost, but the interface is marked as up.
+     * Mark it as down.
+     */
+    if ((link_status == 0) && (sc->last_link_status != 0)) {
+        printk(KERN_WARNING "%s: hardware/physical link down\n", dev->name);
+        sc->last_link_status = 0;
+        /* lmc_reset (sc); Why reset??? The link can go down ok */
+
+        /* Inform the world that link has been lost */
+        dev->flags &= ~IFF_RUNNING;
+    }
+
+    /*
+     * hardware link is up, but the interface is marked as down.
+     * Bring it back up again.
+     */
+     if (link_status != 0 && sc->last_link_status == 0) {
+         printk(KERN_WARNING "%s: hardware/physical link up\n", dev->name);
+         sc->last_link_status = 1;
+         /* lmc_reset (sc); Again why reset??? */
+
+         /* Inform the world that link protocol is back up. */
+         dev->flags |= IFF_RUNNING;
+
+         /* Now we have to tell the syncppp that we had an outage
+          * and that it should deal.  Calling sppp_reopen here
+          * should do the trick, but we may have to call sppp_close
+          * when the link goes down, and call sppp_open here.
+          * Subject to more testing.
+          * --bbraun
+          */
+
+         lmc_proto_reopen(sc);
+
+     }
+
+    /* Call media specific watchdog functions */
+    sc->lmc_media->watchdog(sc);
+
+    /*
+     * Poke the transmitter to make sure it
+     * never stops, even if we run out of mem
+     */
+    LMC_CSR_WRITE(sc, csr_rxpoll, 0);
+
+    /*
+     * Check for code that failed
+     * and try and fix it as appropriate
+     */
+    if(sc->failed_ring == 1){
+        /*
+         * Failed to setup the recv/xmit rin
+         * Try again
+         */
+        sc->failed_ring = 0;
+        lmc_softreset(sc);
+    }
+    if(sc->failed_recv_alloc == 1){
+        /*
+         * We failed to alloc mem in the
+         * interupt halder, go through the rings
+         * and rebuild them
+         */
+        sc->failed_recv_alloc = 0;
+        lmc_softreset(sc);
+    }
+
+
+    /*
+     * remember the timer value
+     */
+kick_timer:
+
+    ticks = LMC_CSR_READ (sc, csr_gp_timer);
+    LMC_CSR_WRITE (sc, csr_gp_timer, 0xffffffffUL);
+    sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff);
+
+    /*
+     * restart this timer.
+     */
+    sc->timer.expires = jiffies + (HZ);
+    add_timer (&sc->timer);
+
+    spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+    lmc_trace(dev, "lmc_watchdog out");
+
+}
+
+static int lmc_init(struct net_device * const dev) /*fold00*/
+{
+    lmc_trace(dev, "lmc_init in");
+    lmc_trace(dev, "lmc_init out");
+	
+    return 0;
+}
+
+/* This initializes each card from lmc_probe() */
+static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*fold00*/
+                                  int chip_id, int subdevice, int board_idx)
+{
+    lmc_softc_t *sc = NULL;
+    u_int16_t AdapModelNum;
+
+    /*
+     * Allocate our own device structure
+     */
+
+#if LINUX_VERSION_CODE < 0x20363
+    dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL);
+#else
+    dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL);
+#endif
+    if (dev == NULL){
+        printk (KERN_ERR "lmc: kmalloc for device failed\n");
+        return NULL;
+    }
+    memset (dev, 0, sizeof (struct net_device));
+
+#ifndef GCOM
+    /*
+     *	Switch to common hdlc%d naming. We name by type not by vendor
+     */
+#if LINUX_VERSION_CODE < 0x20363
+    dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+#else
+    dev->name = ((char *) (dev)) + sizeof (struct net_device);
+#endif
+    
+    dev_alloc_name(dev, "hdlc%d");
+#else
+    /*
+     * GCOM uses LMC vendor name so that clients can know which card
+     * to attach to.
+     */
+    dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+    dev_alloc_name(dev, "lmc%d");
+#endif
+
+    lmc_trace(dev, "lmc_probe1 in");
+    
+    Lmc_Count++;
+
+    if(lmc_first_load == 0){
+        printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION);
+        lmc_first_load = 1;
+    }
+    
+    /*
+     * Allocate space for the private data structure
+     */
+
+    sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL);
+    if (sc == NULL) {
+        printk (KERN_WARNING "%s: Cannot allocate memory for device state\n",
+                dev->name);
+        return (NULL);
+    }
+    memset (sc, 0, sizeof (lmc_softc_t));
+    dev->priv = sc;
+    sc->lmc_device = dev;
+    sc->name = dev->name;
+
+    /* Initialize the sppp layer */
+    /* An ioctl can cause a subsequent detach for raw frame interface */
+    sc->if_type = LMC_PPP;
+    sc->check = 0xBEAFCAFE;
+    dev->base_addr = ioaddr;
+    dev->irq = irq;
+    /*
+     * This will get the protocol layer ready and do any 1 time init's
+     * Must have a valid sc and dev structure
+     */
+    lmc_proto_init(sc);
+
+    lmc_proto_attach(sc);
+
+    /* Just fill in the entries for the device */
+
+    dev->init = lmc_init;
+    dev->type = ARPHRD_HDLC;
+    dev->hard_start_xmit = lmc_start_xmit;
+    dev->open = lmc_open;
+    dev->stop = lmc_close;
+    dev->get_stats = lmc_get_stats;
+    dev->do_ioctl = lmc_ioctl;
+    dev->set_config = lmc_set_config;
+#if LINUX_VERSION_CODE >= 0x20363
+    dev->tx_timeout = lmc_driver_timeout;
+    dev->watchdog_timeo = (HZ); /* 1 second */
+#endif
+    
+    /*
+     * Why were we changing this???
+     dev->tx_queue_len = 100;
+     */
+
+    /* Init the spin lock so can call it latter */
+
+    spin_lock_init(&sc->lmc_lock);
+
+    LMC_SETUP_20_DEV;
+
+    printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq);
+
+    if (register_netdev (dev) != 0) {
+        printk (KERN_ERR "%s: register_netdev failed.\n", dev->name);
+        lmc_proto_detach(sc);
+        kfree (dev->priv);
+        kfree (dev);
+        return NULL;
+    }
+
+    /*
+     * Request the region of registers we need, so that
+     * later on, no one else will take our card away from
+     * us.
+     */
+    request_region (ioaddr, LMC_REG_RANGE, dev->name);
+
+    sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN;
+    sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+
+    switch (subdevice) {
+    case PCI_PRODUCT_LMC_HSSI:
+        printk ("%s: LMC HSSI\n", dev->name);
+        sc->lmc_cardtype = LMC_CARDTYPE_HSSI;
+        sc->lmc_media = &lmc_hssi_media;
+        break;
+    case PCI_PRODUCT_LMC_DS3:
+        printk ("%s: LMC DS3\n", dev->name);
+        sc->lmc_cardtype = LMC_CARDTYPE_DS3;
+        sc->lmc_media = &lmc_ds3_media;
+        break;
+    case PCI_PRODUCT_LMC_SSI:
+        printk ("%s: LMC SSI\n", dev->name);
+        sc->lmc_cardtype = LMC_CARDTYPE_SSI;
+        sc->lmc_media = &lmc_ssi_media;
+        break;
+    case PCI_PRODUCT_LMC_T1:
+        printk ("%s: LMC T1\n", dev->name);
+        sc->lmc_cardtype = LMC_CARDTYPE_T1;
+        sc->lmc_media = &lmc_t1_media;
+        break;
+    default:
+        printk (KERN_WARNING "%s: LMC UNKOWN CARD!\n", dev->name);
+        break;
+    }
+
+    lmc_initcsrs (sc, dev->base_addr, 8);
+
+    lmc_gpio_mkinput (sc, 0xff);
+    sc->lmc_gpio = 0;		/* drive no signals yet */
+
+    sc->lmc_media->defaults (sc);
+
+    sc->lmc_media->set_link_status (sc, LMC_LINK_UP);
+
+    /* verify that the PCI Sub System ID matches the Adapter Model number
+     * from the MII register
+     */
+    AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4;
+
+    if ((AdapModelNum == LMC_ADAP_T1
+         && subdevice == PCI_PRODUCT_LMC_T1) ||		/* detect LMC1200 */
+        (AdapModelNum == LMC_ADAP_SSI
+         && subdevice == PCI_PRODUCT_LMC_SSI) ||	/* detect LMC1000 */
+        (AdapModelNum == LMC_ADAP_DS3
+         && subdevice == PCI_PRODUCT_LMC_DS3) ||	/* detect LMC5245 */
+        (AdapModelNum == LMC_ADAP_HSSI
+         && subdevice == PCI_PRODUCT_LMC_HSSI))
+    {				/* detect LMC5200 */
+
+    }
+    else {
+        printk ("%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n",
+                dev->name, AdapModelNum, subdevice);
+//        return (NULL);
+    }
+    /*
+     * reset clock
+     */
+    LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL);
+
+    sc->board_idx = board_idx;
+
+    memset (&sc->stats, 0, sizeof (struct lmc_statistics));
+
+    sc->stats.check = STATCHECK;
+    sc->stats.version_size = (DRIVER_VERSION << 16) +
+        sizeof (struct lmc_statistics);
+    sc->stats.lmc_cardtype = sc->lmc_cardtype;
+
+    sc->lmc_ok = 0;
+    sc->last_link_status = 0;
+
+    lmc_trace(dev, "lmc_probe1 out");
+
+    return dev;
+}
+
+
+/* This is the entry point.  This is what is called immediatly. */
+/* This goes out and finds the card */
+
+int lmc_probe_fake(struct net_device *dev) /*fold00*/
+{
+    lmc_probe(NULL);
+    /* Return 1 to unloaded bogus device */
+    return 1;
+}
+
+int lmc_probe (struct net_device *dev) /*fold00*/
+{
+    int pci_index = 0;
+#if LINUX_VERSION_CODE >= 0x20155
+    unsigned long pci_ioaddr;
+    unsigned short pci_command;
+    unsigned int pci_irq_line;
+#else
+    unsigned char pci_irq_line;
+    u32 pci_ioaddr;
+#endif
+    u16 vendor, subvendor, device, subdevice;
+    u32 foundaddr = 0;
+    unsigned char pci_bus, pci_device_fn;
+    u8 intcf = 0;
+
+    /* The card is only available on PCI, so if we don't have a
+     * PCI bus, we are in trouble.
+     */
+
+    if (!LMC_PCI_PRESENT()) {
+/*        printk ("%s: We really want a pci bios!\n", dev->name);*/
+        return -1;
+    }
+    /* Loop basically until we don't find anymore. */
+    while (pci_index < 0xff){
+        /* The tulip is considered an ethernet class of card... */
+        if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+                                pci_index, &pci_bus,
+                                &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
+            /* No card found on this pass */
+            break;
+        }
+        /* Read the info we need to determine if this is
+         * our card or not
+         */
+#if LINUX_VERSION_CODE >= 0x20155
+        vendor = pci_find_slot (pci_bus, pci_device_fn)->vendor;
+        device = pci_find_slot (pci_bus, pci_device_fn)->device;
+        pci_irq_line = pci_find_slot (pci_bus, pci_device_fn)->irq;
+#if LINUX_VERSION_CODE < 0x20363
+        pci_ioaddr = pci_find_slot (pci_bus, pci_device_fn)->base_address[0];
+#else
+        pci_ioaddr = pci_resource_start (pci_find_slot (pci_bus, pci_device_fn), 0);
+#endif
+        pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
+                              PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
+        pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
+                              PCI_SUBSYSTEM_ID, &subdevice);
+        /*
+         * SPARC PCI Bios doesn't set the BUS Master bit, unlike intel
+         * Without it we won't do much packet work
+         * Do this to everyone
+         */
+        pci_read_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND,
+                             &pci_command);
+        pci_command |= PCI_COMMAND_MASTER;
+        pci_write_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND,
+                              pci_command);
+#else
+        pcibios_read_config_word (pci_bus, pci_device_fn,
+                                  PCI_VENDOR_ID, &vendor);
+        pcibios_read_config_word (pci_bus, pci_device_fn,
+                                  PCI_DEVICE_ID, &device);
+        pcibios_read_config_byte (pci_bus, pci_device_fn,
+                                  PCI_INTERRUPT_LINE, &pci_irq_line);
+        pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+        pcibios_read_config_word (pci_bus, pci_device_fn,
+                                  PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
+        pcibios_read_config_word (pci_bus, pci_device_fn,
+                                  PCI_SUBSYSTEM_ID, &subdevice);
+#endif
+
+        /* Align the io address on the 32 bit boundry just in case */
+        pci_ioaddr &= ~3;
+
+        /*
+         * Make sure it's the correct card.  CHECK SUBVENDOR ID!
+         * There are lots of tulip's out there.
+         * Also check the region of registers we will soon be
+         * poking, to make sure no one else has reserved them.
+         * This prevents taking someone else's device.
+         *
+         * Check either the subvendor or the subdevice, some systems reverse
+         * the setting in the bois, seems to be version and arch dependant?
+         * Fix the two variables
+         *
+         */
+        if (!(check_region (pci_ioaddr, LMC_REG_RANGE)) &&
+            (vendor == CORRECT_VENDOR_ID) &&
+            (device == CORRECT_DEV_ID) &&
+            ((subvendor == PCI_VENDOR_LMC)  || (subdevice == PCI_VENDOR_LMC))){
+            struct net_device *cur, *prev = NULL;
+
+            /* Fix the error, exchange the two values */
+            if(subdevice == PCI_VENDOR_LMC){
+                subdevice = subvendor;
+                subvendor = PCI_VENDOR_LMC ;
+            }
+
+            /* Make the call to actually setup this card */
+            dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line,
+                              device, subdevice, cards_found);
+            if (dev == NULL) {
+                printk ("lmc_probe: lmc_probe1 failed\n");
+                goto lmc_probe_next_card;
+            }
+            /* insert the device into the chain of lmc devices */
+            for (cur = Lmc_root_dev;
+                 cur != NULL;
+                 cur = ((lmc_softc_t *) cur->priv)->next_module) {
+                prev = cur;
+            }
+
+            if (prev == NULL)
+                Lmc_root_dev = dev;
+            else
+                ((lmc_softc_t *) prev->priv)->next_module = dev;
+
+            ((lmc_softc_t *) dev->priv)->next_module = NULL;
+            /* end insert */
+
+            foundaddr = dev->base_addr;
+
+            cards_found++;
+            intcf++;
+        }
+    lmc_probe_next_card:
+        pci_index++;
+    }
+
+    if (cards_found < 1)
+        return -1;
+
+#if LINUX_VERSION_CODE >= 0x20200
+    return foundaddr;
+#else
+    return 0;
+#endif
+}
+
+/* After this is called, packets can be sent.
+ * Does not initialize the addresses
+ */
+static int lmc_open (struct net_device *dev) /*fold00*/
+{
+    lmc_softc_t *sc = dev->priv;
+
+    lmc_trace(dev, "lmc_open in");
+
+    lmc_led_on(sc, LMC_DS3_LED0);
+
+    lmc_dec_reset (sc);
+    lmc_reset (sc);
+
+    LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+    LMC_EVENT_LOG(LMC_EVENT_RESET2,
+                  lmc_mii_readreg (sc, 0, 16),
+                  lmc_mii_readreg (sc, 0, 17));
+
+
+    if (sc->lmc_ok){
+        lmc_trace(dev, "lmc_open lmc_ok out");
+        return (0);
+    }
+
+    lmc_softreset (sc);
+
+    /* Since we have to use PCI bus, this should work on x86,alpha,ppc */
+    if (request_irq (dev->irq, &lmc_interrupt, SA_SHIRQ, dev->name, dev)){
+        printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq);
+        lmc_trace(dev, "lmc_open irq failed out");
+        return -EAGAIN;
+    }
+    sc->got_irq = 1;
+
+    /* Assert Terminal Active */
+    sc->lmc_miireg16 |= LMC_MII16_LED_ALL;
+    sc->lmc_media->set_link_status (sc, LMC_LINK_UP);
+
+    /*
+     * reset to last state.
+     */
+    sc->lmc_media->set_status (sc, NULL);
+
+    /* setup default bits to be used in tulip_desc_t transmit descriptor
+     * -baz */
+    sc->TxDescriptControlInit = (
+                                 LMC_TDES_INTERRUPT_ON_COMPLETION
+                                 | LMC_TDES_FIRST_SEGMENT
+                                 | LMC_TDES_LAST_SEGMENT
+                                 | LMC_TDES_SECOND_ADDR_CHAINED
+                                 | LMC_TDES_DISABLE_PADDING
+                                );
+
+    if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) {
+        /* disable 32 bit CRC generated by ASIC */
+        sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE;
+    }
+    sc->lmc_media->set_crc_length(sc, sc->ictl.crc_length);
+    /* Acknoledge the Terminal Active and light LEDs */
+
+    /* dev->flags |= IFF_UP; */
+
+    lmc_proto_open(sc);
+
+    dev->do_ioctl = lmc_ioctl;
+
+
+    LMC_XMITTER_INIT(dev);
+    
+#if LINUX_VERSION_CODE < 0x20363
+    dev->start = 1;
+#endif
+    
+    sc->stats.tx_tbusy0++ ;
+
+    MOD_INC_USE_COUNT;
+
+    /*
+     * select what interrupts we want to get
+     */
+    sc->lmc_intrmask = 0;
+    /* Should be using the default interrupt mask defined in the .h file. */
+    sc->lmc_intrmask |= (TULIP_STS_NORMALINTR
+                         | TULIP_STS_RXINTR
+                         | TULIP_STS_TXINTR
+                         | TULIP_STS_ABNRMLINTR
+                         | TULIP_STS_SYSERROR
+                         | TULIP_STS_TXSTOPPED
+                         | TULIP_STS_TXUNDERFLOW
+                         | TULIP_STS_RXSTOPPED
+		         | TULIP_STS_RXNOBUF
+                        );
+    LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+
+    sc->lmc_cmdmode |= TULIP_CMD_TXRUN;
+    sc->lmc_cmdmode |= TULIP_CMD_RXRUN;
+    LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+    sc->lmc_ok = 1; /* Run watchdog */
+
+    /*
+     * Set the if up now - pfb
+     */
+
+    sc->last_link_status = 1;
+
+    /*
+     * Setup a timer for the watchdog on probe, and start it running.
+     * Since lmc_ok == 0, it will be a NOP for now.
+     */
+    init_timer (&sc->timer);
+    sc->timer.expires = jiffies + HZ;
+    sc->timer.data = (unsigned long) dev;
+    sc->timer.function = &lmc_watchdog;
+    add_timer (&sc->timer);
+
+    lmc_trace(dev, "lmc_open out");
+
+    return (0);
+}
+
+/* Total reset to compensate for the AdTran DSU doing bad things
+ *  under heavy load
+ */
+
+static void lmc_running_reset (struct net_device *dev) /*fold00*/
+{
+
+    lmc_softc_t *sc = (lmc_softc_t *) dev->priv;
+
+    lmc_trace(dev, "lmc_runnig_reset in");
+
+    /* stop interrupts */
+    /* Clear the interrupt mask */
+    LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+
+    lmc_dec_reset (sc);
+    lmc_reset (sc);
+    lmc_softreset (sc);
+    /* sc->lmc_miireg16 |= LMC_MII16_LED_ALL; */
+    sc->lmc_media->set_link_status (sc, 1);
+    sc->lmc_media->set_status (sc, NULL);
+
+    //dev->flags |= IFF_RUNNING;
+    
+    LMC_XMITTER_FREE(dev);
+
+    sc->lmc_txfull = 0;
+    sc->stats.tx_tbusy0++ ;
+
+    sc->lmc_intrmask = TULIP_DEFAULT_INTR_MASK;
+    LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+
+    sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN);
+    LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+    lmc_trace(dev, "lmc_runnin_reset_out");
+}
+
+
+/* This is what is called when you ifconfig down a device.
+ * This disables the timer for the watchdog and keepalives,
+ * and disables the irq for dev.
+ */
+static int lmc_close (struct net_device *dev) /*fold00*/
+{
+    /* not calling release_region() as we should */
+    lmc_softc_t *sc;
+
+    lmc_trace(dev, "lmc_close in");
+    
+    sc = dev->priv;
+    sc->lmc_ok = 0;
+    sc->lmc_media->set_link_status (sc, 0);
+    del_timer (&sc->timer);
+    lmc_proto_close(sc);
+    lmc_ifdown (dev);
+
+    lmc_trace(dev, "lmc_close out");
+    
+    return 0;
+}
+
+/* Ends the transfer of packets */
+/* When the interface goes down, this is called */
+static int lmc_ifdown (struct net_device *dev) /*fold00*/
+{
+    lmc_softc_t *sc = dev->priv;
+    u32 csr6;
+    int i;
+
+    lmc_trace(dev, "lmc_ifdown in");
+    
+    /* Don't let anything else go on right now */
+    //    dev->start = 0;
+    LMC_XMITTER_BUSY(dev);
+    sc->stats.tx_tbusy1++ ;
+
+    /* stop interrupts */
+    /* Clear the interrupt mask */
+    LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+
+    /* Stop Tx and Rx on the chip */
+    csr6 = LMC_CSR_READ (sc, csr_command);
+    csr6 &= ~LMC_DEC_ST;		/* Turn off the Transmission bit */
+    csr6 &= ~LMC_DEC_SR;		/* Turn off the Recieve bit */
+    LMC_CSR_WRITE (sc, csr_command, csr6);
+
+    dev->flags &= ~IFF_RUNNING;
+
+    sc->stats.rx_missed_errors +=
+        LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+
+    /* release the interrupt */
+    if(sc->got_irq == 1){
+        free_irq (dev->irq, dev);
+        sc->got_irq = 0;
+    }
+
+    /* free skbuffs in the Rx queue */
+    for (i = 0; i < LMC_RXDESCS; i++)
+    {
+        struct sk_buff *skb = sc->lmc_rxq[i];
+        sc->lmc_rxq[i] = 0;
+        sc->lmc_rxring[i].status = 0;
+        sc->lmc_rxring[i].length = 0;
+        sc->lmc_rxring[i].buffer1 = 0xDEADBEEF;
+        if (skb != NULL)
+        {
+            LMC_SKB_FREE(skb, 1);
+            LMC_DEV_KFREE_SKB (skb);
+        }
+        sc->lmc_rxq[i] = NULL;
+    }
+
+    for (i = 0; i < LMC_TXDESCS; i++)
+    {
+        if (sc->lmc_txq[i] != NULL)
+            LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+        sc->lmc_txq[i] = NULL;
+    }
+
+    lmc_led_off (sc, LMC_MII16_LED_ALL);
+
+    LMC_XMITTER_FREE(dev);
+    sc->stats.tx_tbusy0++ ;
+
+    lmc_trace(dev, "lmc_ifdown out");
+
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/* Interrupt handling routine.  This will take an incoming packet, or clean
+ * up after a trasmit.
+ */
+static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
+{
+    struct net_device *dev = (struct net_device *) dev_instance;
+    lmc_softc_t *sc;
+    u32 csr;
+    int i;
+    s32 stat;
+    unsigned int badtx;
+    u32 firstcsr;
+    int max_work = LMC_RXDESCS;
+
+    lmc_trace(dev, "lmc_interrupt in");
+
+    sc = dev->priv;
+    
+    spin_lock(&sc->lmc_lock);
+
+    /*
+     * Read the csr to find what interupts we have (if any)
+     */
+    csr = LMC_CSR_READ (sc, csr_status);
+
+    /*
+     * Make sure this is our interrupt
+     */
+    if ( ! (csr & sc->lmc_intrmask)) {
+        goto lmc_int_fail_out;
+    }
+
+    firstcsr = csr;
+
+    /* always go through this loop at least once */
+    while (csr & sc->lmc_intrmask) {
+        /*
+         * Clear interupt bits, we handle all case below
+         */
+        LMC_CSR_WRITE (sc, csr_status, csr);
+
+        /*
+         * One of
+         *  - Transmit process timed out CSR5<1>
+         *  - Transmit jabber timeout    CSR5<3>
+         *  - Transmit underflow         CSR5<5>
+         *  - Transmit Receiver buffer unavailable CSR5<7>
+         *  - Receive process stopped    CSR5<8>
+         *  - Receive watchdog timeout   CSR5<9>
+         *  - Early transmit interrupt   CSR5<10>
+         *
+         * Is this really right? Should we do a running reset for jabber?
+         * (being a WAN card and all)
+         */
+        if (csr & TULIP_STS_ABNRMLINTR){
+            lmc_running_reset (dev);
+            break;
+        }
+        
+        if (csr & TULIP_STS_RXINTR){
+            lmc_trace(dev, "rx interupt");
+            lmc_rx (dev);
+            
+        }
+        if (csr & (TULIP_STS_TXINTR | TULIP_STS_TXNOBUF | TULIP_STS_TXSTOPPED)) {
+
+	    int		n_compl = 0 ;
+            /* reset the transmit timeout detection flag -baz */
+            sc->stats.tx_NoCompleteCnt = 0;
+
+            badtx = sc->lmc_taint_tx;
+            i = badtx % LMC_TXDESCS;
+
+            while ((badtx < sc->lmc_next_tx)) {
+                stat = sc->lmc_txring[i].status;
+
+                LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat,
+						 sc->lmc_txring[i].length);
+                /*
+                 * If bit 31 is 1 the tulip owns it break out of the loop
+                 */
+                if (stat & 0x80000000)
+                    break;
+
+		n_compl++ ;		/* i.e., have an empty slot in ring */
+                /*
+                 * If we have no skbuff or have cleared it
+                 * Already continue to the next buffer
+                 */
+                if (sc->lmc_txq[i] == NULL)
+                    continue;
+
+                /*
+                 * Check the total error summary to look for any errors
+                 */
+                if (stat & 0x8000) {
+                    sc->stats.tx_errors++;
+                    if (stat & 0x4104)
+                        sc->stats.tx_aborted_errors++;
+                    if (stat & 0x0C00)
+                        sc->stats.tx_carrier_errors++;
+                    if (stat & 0x0200)
+                        sc->stats.tx_window_errors++;
+                    if (stat & 0x0002)
+                        sc->stats.tx_fifo_errors++;
+                }
+                else {
+                    
+#if LINUX_VERSION_CODE >= 0x20200
+                    sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff;
+#endif
+                    
+                    sc->stats.tx_packets++;
+                }
+                
+                //                LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+                dev_kfree_skb_irq(sc->lmc_txq[i]);
+                sc->lmc_txq[i] = 0;
+
+                badtx++;
+                i = badtx % LMC_TXDESCS;
+            }
+
+            if (sc->lmc_next_tx - badtx > LMC_TXDESCS)
+            {
+                printk ("%s: out of sync pointer\n", dev->name);
+                badtx += LMC_TXDESCS;
+            }
+            LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0);
+            sc->lmc_txfull = 0;
+            LMC_XMITTER_FREE(dev);
+            sc->stats.tx_tbusy0++ ;
+#if LINUX_VERSION_CODE < 0x20363
+            mark_bh (NET_BH);	/* Tell Linux to give me more packets */
+#endif
+
+
+#ifdef DEBUG
+            sc->stats.dirtyTx = badtx;
+            sc->stats.lmc_next_tx = sc->lmc_next_tx;
+            sc->stats.lmc_txfull = sc->lmc_txfull;
+#if LINUX_VERSION_CODE < 0x20363
+            sc->stats.tbusy = dev->tbusy;
+#endif
+#endif
+            sc->lmc_taint_tx = badtx;
+
+            /*
+             * Why was there a break here???
+             */
+        }			/* end handle transmit interrupt */
+
+        if (csr & TULIP_STS_SYSERROR) {
+            u32 error;
+            printk (KERN_WARNING "%s: system bus error csr: %#8.8x\n", dev->name, csr);
+            error = csr>>23 & 0x7;
+            switch(error){
+            case 0x000:
+                printk(KERN_WARNING "%s: Parity Fault (bad)\n", dev->name);
+                break;
+            case 0x001:
+                printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name);
+                break;
+            case 0x010:
+                printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name);
+                break;
+            default:
+                printk(KERN_WARNING "%s: This bus error code was supposed to be reserved!\n", dev->name);
+            }
+            lmc_dec_reset (sc);
+            lmc_reset (sc);
+            LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+            LMC_EVENT_LOG(LMC_EVENT_RESET2,
+                          lmc_mii_readreg (sc, 0, 16),
+                          lmc_mii_readreg (sc, 0, 17));
+
+        }
+
+        
+        if(max_work-- <= 0)
+            break;
+        
+        /*
+         * Get current csr status to make sure
+         * we've cleared all interupts
+         */
+        csr = LMC_CSR_READ (sc, csr_status);
+    }				/* end interrupt loop */
+    LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr);
+
+lmc_int_fail_out:
+
+    spin_unlock(&sc->lmc_lock);
+
+    lmc_trace(dev, "lmc_interrupt out");
+
+    return;
+}
+
+static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
+{
+    lmc_softc_t *sc;
+    u32 flag;
+    int entry;
+    int ret = 0;
+    LMC_SPIN_FLAGS;
+
+    lmc_trace(dev, "lmc_start_xmit in");
+
+    sc = dev->priv;
+
+    spin_lock_irqsave(&sc->lmc_lock, flags);
+
+    /*
+     * If the transmitter is busy
+     * this must be the 5 second polling
+     * from the kernel which called us.
+     * Poke the chip and try to get it running
+     *
+     */
+#if LINUX_VERSION_CODE < 0x20363
+    if(dev->tbusy != 0){
+        u32 csr6;
+
+        printk("%s: Xmitter busy|\n", dev->name);
+
+	sc->stats.tx_tbusy_calls++ ;
+        if (jiffies - dev->trans_start < TX_TIMEOUT) {
+            ret = 1;
+            goto lmc_start_xmit_bug_out;
+        }
+
+        /*
+         * Chip seems to have locked up
+         * Reset it
+         * This whips out all our decriptor
+         * table and starts from scartch
+         */
+
+        LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO,
+                      LMC_CSR_READ (sc, csr_status),
+                      sc->stats.tx_ProcTimeout);
+
+        lmc_running_reset (dev);
+
+        LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+        LMC_EVENT_LOG(LMC_EVENT_RESET2,
+                      lmc_mii_readreg (sc, 0, 16),
+                      lmc_mii_readreg (sc, 0, 17));
+
+        /* restart the tx processes */
+        csr6 = LMC_CSR_READ (sc, csr_command);
+        LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002);
+        LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002);
+
+        /* immediate transmit */
+        LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+        sc->stats.tx_errors++;
+        sc->stats.tx_ProcTimeout++;	/* -baz */
+
+        dev->trans_start = jiffies;
+
+        ret = 1;
+        goto lmc_start_xmit_bug_out;
+    }
+#endif
+    /* normal path, tbusy known to be zero */
+
+    entry = sc->lmc_next_tx % LMC_TXDESCS;
+
+    sc->lmc_txq[entry] = skb;
+    sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data);
+
+    LMC_CONSOLE_LOG("xmit", skb->data, skb->len);
+
+#ifndef GCOM
+    /* If the queue is less than half full, don't interrupt */
+    if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS / 2)
+    {
+        /* Do not interrupt on completion of this packet */
+        flag = 0x60000000;
+        LMC_XMITTER_FREE(dev);
+    }
+    else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2)
+    {
+        /* This generates an interrupt on completion of this packet */
+        flag = 0xe0000000;
+        LMC_XMITTER_FREE(dev);
+    }
+    else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1)
+    {
+        /* Do not interrupt on completion of this packet */
+        flag = 0x60000000;
+        LMC_XMITTER_FREE(dev);
+    }
+    else
+    {
+        /* This generates an interrupt on completion of this packet */
+        flag = 0xe0000000;
+        sc->lmc_txfull = 1;
+        LMC_XMITTER_BUSY(dev);
+    }
+#else
+    flag = LMC_TDES_INTERRUPT_ON_COMPLETION;
+
+    if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1)
+    {				/* ring full, go busy */
+        sc->lmc_txfull = 1;
+        LMC_XMITTER_BUSY(dev);
+        sc->stats.tx_tbusy1++ ;
+        LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0);
+    }
+#endif
+
+
+    if (entry == LMC_TXDESCS - 1)	/* last descriptor in ring */
+	flag |= LMC_TDES_END_OF_RING;	/* flag as such for Tulip */
+
+    /* don't pad small packets either */
+    flag = sc->lmc_txring[entry].length = (skb->len) | flag |
+						sc->TxDescriptControlInit;
+
+    /* set the transmit timeout flag to be checked in
+     * the watchdog timer handler. -baz
+     */
+
+    sc->stats.tx_NoCompleteCnt++;
+    sc->lmc_next_tx++;
+
+    /* give ownership to the chip */
+    LMC_EVENT_LOG(LMC_EVENT_XMT, flag, entry);
+    sc->lmc_txring[entry].status = 0x80000000;
+
+    /* send now! */
+    LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+    dev->trans_start = jiffies;
+
+#if LINUX_VERSION_CODE < 0x20363
+lmc_start_xmit_bug_out:
+#endif
+
+    spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+    lmc_trace(dev, "lmc_start_xmit_out");
+    return ret;
+}
+
+
+static int lmc_rx (struct net_device *dev) /*fold00*/
+{
+    lmc_softc_t *sc;
+    int i;
+    int rx_work_limit = LMC_RXDESCS;
+    unsigned int next_rx;
+    int rxIntLoopCnt;		/* debug -baz */
+    int localLengthErrCnt = 0;
+    long stat;
+    struct sk_buff *skb, *nsb;
+    u16 len;
+
+    lmc_trace(dev, "lmc_rx in");
+
+    sc = dev->priv;
+
+    lmc_led_on(sc, LMC_DS3_LED3);
+
+    rxIntLoopCnt = 0;		/* debug -baz */
+
+    i = sc->lmc_next_rx % LMC_RXDESCS;
+    next_rx = sc->lmc_next_rx;
+
+    while (((stat = sc->lmc_rxring[i].status) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4)
+    {
+        rxIntLoopCnt++;		/* debug -baz */
+        len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER);
+        if ((stat & 0x0300) != 0x0300) {  /* Check first segment and last segment */
+            if ((stat & 0x0000ffff) != 0x7fff) {
+                /* Oversized frame */
+                sc->stats.rx_length_errors++;
+                goto skip_packet;
+            }
+        }
+
+        if(stat & 0x00000008){ /* Catch a dribbling bit error */
+            sc->stats.rx_errors++;
+            sc->stats.rx_frame_errors++;
+            goto skip_packet;
+        }
+
+
+        if(stat & 0x00000004){ /* Catch a CRC error by the Xilinx */
+            sc->stats.rx_errors++;
+            sc->stats.rx_crc_errors++;
+            goto skip_packet;
+        }
+
+
+        if (len > LMC_PKT_BUF_SZ){
+            sc->stats.rx_length_errors++;
+            localLengthErrCnt++;
+            goto skip_packet;
+        }
+
+        if (len < sc->lmc_crcSize + 2) {
+            sc->stats.rx_length_errors++;
+            sc->stats.rx_SmallPktCnt++;
+            localLengthErrCnt++;
+            goto skip_packet;
+        }
+
+        if(stat & 0x00004000){
+            printk(KERN_WARNING "%s: Receiver descriptor error, receiver out of sync?\n", dev->name);
+        }
+
+        len -= sc->lmc_crcSize;
+
+        skb = sc->lmc_rxq[i];
+
+        /*
+         * We ran out of memory at some point
+         * just allocate an skb buff and continue.
+         */
+        
+        if(skb == 0x0){
+            nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+            if (nsb) {
+                LMC_SKB_FREE(nsb, 1);
+                sc->lmc_rxq[i] = nsb;
+                nsb->dev = dev;
+                sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+            }
+            sc->failed_recv_alloc = 1;
+            goto skip_packet;
+        }
+        
+        dev->last_rx = jiffies;
+        sc->stats.rx_packets++;
+
+        LMC_CONSOLE_LOG("recv", skb->data, len);
+
+        /*
+         * I'm not sure of the sanity of this
+         * Packets could be arriving at a constant
+         * 44.210mbits/sec and we're going to copy
+         * them into a new buffer??
+         */
+        
+        if(len > (LMC_MTU - (LMC_MTU>>2))){ /* len > LMC_MTU * 0.75 */
+            /*
+             * If it's a large packet don't copy it just hand it up
+             */
+        give_it_anyways:
+
+            sc->lmc_rxq[i] = 0x0;
+            sc->lmc_rxring[i].buffer1 = 0x0;
+
+            skb_put (skb, len);
+            skb->protocol = lmc_proto_type(sc, skb);
+            skb->protocol = htons(ETH_P_WAN_PPP);
+            skb->mac.raw = skb->data;
+//            skb->nh.raw = skb->data;
+            skb->dev = dev;
+            lmc_proto_netif(sc, skb);
+
+            /*
+             * This skb will be destroyed by the upper layers, make a new one
+             */
+            nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+            if (nsb) {
+                LMC_SKB_FREE(nsb, 1);
+                sc->lmc_rxq[i] = nsb;
+                nsb->dev = dev;
+                sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+                /* Transfered to 21140 below */
+            }
+            else {
+                /*
+                 * We've run out of memory, stop trying to allocate
+                 * memory and exit the interupt handler
+                 *
+                 * The chip may run out of receivers and stop
+                 * in which care we'll try to allocate the buffer
+                 * again.  (once a second)
+                 */
+                sc->stats.rx_BuffAllocErr++;
+                LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len);
+                sc->failed_recv_alloc = 1;
+                goto skip_out_of_mem;
+            }
+        }
+        else {
+            nsb = dev_alloc_skb(len);
+            if(!nsb) {
+                goto give_it_anyways;
+            }
+            memcpy(skb_put(nsb, len), skb->data, len);
+            
+            nsb->protocol = lmc_proto_type(sc, skb);
+            nsb->mac.raw = nsb->data;
+//            nsb->nh.raw = nsb->data;
+            nsb->dev = dev;
+            lmc_proto_netif(sc, nsb);
+        }
+
+    skip_packet:
+        LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len);
+        sc->lmc_rxring[i].status = DESC_OWNED_BY_DC21X4;
+
+        sc->lmc_next_rx++;
+        i = sc->lmc_next_rx % LMC_RXDESCS;
+        rx_work_limit--;
+        if (rx_work_limit < 0)
+            break;
+    }
+
+    /* detect condition for LMC1000 where DSU cable attaches and fills
+     * descriptors with bogus packets
+     *
+    if (localLengthErrCnt > LMC_RXDESCS - 3) {
+        sc->stats.rx_BadPktSurgeCnt++;
+        LMC_EVENT_LOG(LMC_EVENT_BADPKTSURGE,
+                      localLengthErrCnt,
+                      sc->stats.rx_BadPktSurgeCnt);
+    } */
+
+    /* save max count of receive descriptors serviced */
+    if (rxIntLoopCnt > sc->stats.rxIntLoopCnt) {
+        sc->stats.rxIntLoopCnt = rxIntLoopCnt;	/* debug -baz */
+    }
+
+#ifdef DEBUG
+    if (rxIntLoopCnt == 0)
+    {
+        for (i = 0; i < LMC_RXDESCS; i++)
+        {
+            if ((sc->lmc_rxring[i].status & LMC_RDES_OWN_BIT)
+                != DESC_OWNED_BY_DC21X4)
+            {
+                rxIntLoopCnt++;
+            }
+        }
+        LMC_EVENT_LOG(LMC_EVENT_RCVEND, rxIntLoopCnt, 0);
+    }
+#endif
+
+
+    lmc_led_off(sc, LMC_DS3_LED3);
+
+skip_out_of_mem:
+
+    lmc_trace(dev, "lmc_rx out");
+
+    return 0;
+}
+
+static struct enet_statistics *lmc_get_stats (struct net_device *dev) /*fold00*/
+{
+    lmc_softc_t *sc;
+    LMC_SPIN_FLAGS;
+
+    lmc_trace(dev, "lmc_get_stats in");
+
+    sc = dev->priv;
+
+    spin_lock_irqsave(&sc->lmc_lock, flags);
+
+    sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+
+    spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+    lmc_trace(dev, "lmc_get_stats out");
+
+    return (struct enet_statistics *) &sc->stats;
+}
+
+#ifdef MODULE
+
+int init_module (void) /*fold00*/
+{
+    printk ("lmc: module loaded\n");
+
+    /* Have lmc_probe search for all the cards, and allocate devices */
+    if (lmc_probe (NULL) < 0)
+        return -EIO;
+
+    return 0;
+}
+
+void cleanup_module (void) /*fold00*/
+{
+    struct net_device *dev, *next;
+    lmc_softc_t *sc;
+
+    /* we have no pointer to our devices, since they are all dynamically
+     * allocated.  So, here we loop through all the network devices
+     * looking for ours.  When found, dispose of them properly.
+     */
+
+    for (dev = Lmc_root_dev;
+         dev != NULL;
+         dev = next )
+    {
+
+        next = ((lmc_softc_t *) dev->priv)->next_module; /* get it now before we deallocate it */
+        printk ("%s: removing...\n", dev->name);
+
+        /* close the syncppp stuff, and release irq. Close is run on unreg net */
+        lmc_close (dev);
+	sc = dev->priv;
+        if (sc != NULL)
+            lmc_proto_detach(sc);
+
+        /* Remove the device from the linked list */
+        unregister_netdev (dev);
+
+        /* Let go of the io region */;
+        release_region (dev->base_addr, LMC_REG_RANGE);
+
+        /* free our allocated structures. */
+        kfree (dev->priv);
+        dev->priv = NULL;
+
+        kfree ((struct ppp_device *) dev);
+        dev = NULL;
+    }
+
+
+    Lmc_root_dev = NULL;
+    printk ("lmc module unloaded\n");
+}
+#endif
+
+unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/
+{
+    int i;
+    int command = (0xf6 << 10) | (devaddr << 5) | regno;
+    int retval = 0;
+
+    lmc_trace(sc->lmc_device, "lmc_mii_readreg in");
+
+    LMC_MII_SYNC (sc);
+
+    lmc_trace(sc->lmc_device, "lmc_mii_readreg: done sync");
+
+    for (i = 15; i >= 0; i--)
+    {
+        int dataval = (command & (1 << i)) ? 0x20000 : 0;
+
+        LMC_CSR_WRITE (sc, csr_9, dataval);
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+        LMC_CSR_WRITE (sc, csr_9, dataval | 0x10000);
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+    }
+
+    lmc_trace(sc->lmc_device, "lmc_mii_readreg: done1");
+
+    for (i = 19; i > 0; i--)
+    {
+        LMC_CSR_WRITE (sc, csr_9, 0x40000);
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+        retval = (retval << 1) | ((LMC_CSR_READ (sc, csr_9) & 0x80000) ? 1 : 0);
+        LMC_CSR_WRITE (sc, csr_9, 0x40000 | 0x10000);
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+    }
+
+    lmc_trace(sc->lmc_device, "lmc_mii_readreg out");
+
+    return (retval >> 1) & 0xffff;
+}
+
+void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data) /*fold00*/
+{
+    int i = 32;
+    int command = (0x5002 << 16) | (devaddr << 23) | (regno << 18) | data;
+
+    lmc_trace(sc->lmc_device, "lmc_mii_writereg in");
+
+    LMC_MII_SYNC (sc);
+
+    i = 31;
+    while (i >= 0)
+    {
+        int datav;
+
+        if (command & (1 << i))
+            datav = 0x20000;
+        else
+            datav = 0x00000;
+
+        LMC_CSR_WRITE (sc, csr_9, datav);
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+        LMC_CSR_WRITE (sc, csr_9, (datav | 0x10000));
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+        i--;
+    }
+
+    i = 2;
+    while (i > 0)
+    {
+        LMC_CSR_WRITE (sc, csr_9, 0x40000);
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+        LMC_CSR_WRITE (sc, csr_9, 0x50000);
+        lmc_delay ();
+        /* __SLOW_DOWN_IO; */
+        i--;
+    }
+
+    lmc_trace(sc->lmc_device, "lmc_mii_writereg out");
+}
+
+static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/
+{
+    int i;
+
+    lmc_trace(sc->lmc_device, "lmc_softreset in");
+
+    /* Initialize the recieve rings and buffers. */
+    sc->lmc_txfull = 0;
+    sc->lmc_next_rx = 0;
+    sc->lmc_next_tx = 0;
+    sc->lmc_taint_rx = 0;
+    sc->lmc_taint_tx = 0;
+
+    /*
+     * Setup each one of the receiver buffers
+     * allocate an skbuff for each one, setup the the descriptor table
+     * and point each buffer at the next one
+     */
+
+    for (i = 0; i < LMC_RXDESCS; i++)
+    {
+        struct sk_buff *skb;
+
+        if (sc->lmc_rxq[i] == NULL)
+        {
+            skb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+            if(skb == NULL){
+                printk(KERN_WARNING "%s: Failed to allocate receiver ring, will try again\n", sc->name);
+                sc->failed_ring = 1;
+                break;
+            }
+            else{
+                sc->lmc_rxq[i] = skb;
+            }
+        }
+        else
+        {
+            skb = sc->lmc_rxq[i];
+        }
+
+        skb->dev = sc->lmc_device;
+        LMC_SKB_FREE(skb, 1);
+
+        /* owned by 21140 */
+        sc->lmc_rxring[i].status = 0x80000000;
+
+        /* used to be PKT_BUF_SZ now uses skb since we loose some to head room */
+        sc->lmc_rxring[i].length = skb->end - skb->data;
+
+        /* use to be tail which is dumb since you're thinking why write
+         * to the end of the packj,et but since there's nothing there tail == data
+         */
+        sc->lmc_rxring[i].buffer1 = virt_to_bus (skb->data);
+
+        /* This is fair since the structure is static and we have the next address */
+        sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i + 1]);
+
+    }
+
+    /*
+     * Sets end of ring
+     */
+    sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */
+    sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */
+    LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */
+
+
+    /* Initialize the transmit rings and buffers */
+    for (i = 0; i < LMC_TXDESCS; i++)
+    {
+        if (sc->lmc_txq[i] != NULL){		/* have buffer */
+            dev_kfree_skb(sc->lmc_txq[i]);	/* free it */
+            sc->stats.tx_dropped++;      /* We just dropped a packet */
+        }
+        sc->lmc_txq[i] = 0;
+        sc->lmc_txring[i].status = 0x00000000;
+        sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]);
+    }
+    sc->lmc_txring[i - 1].buffer2 = virt_to_bus (&sc->lmc_txring[0]);
+    LMC_CSR_WRITE (sc, csr_txlist, virt_to_bus (sc->lmc_txring));
+
+    lmc_trace(sc->lmc_device, "lmc_softreset out");
+}
+
+static int lmc_set_config(struct net_device *dev, struct ifmap *map) /*fold00*/
+{
+    lmc_trace(dev, "lmc_set_config in");
+    lmc_trace(dev, "lmc_set_config out");
+    return -EOPNOTSUPP;
+}
+
+void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_gpio_mkinput in");
+    sc->lmc_gpio_io &= ~bits;
+    LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+    lmc_trace(sc->lmc_device, "lmc_gpio_mkinput out");
+}
+
+void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput in");
+    sc->lmc_gpio_io |= bits;
+    LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+    lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput out");
+}
+
+void lmc_led_on(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_led_on in");
+    if((~sc->lmc_miireg16) & led){ /* Already on! */
+        lmc_trace(sc->lmc_device, "lmc_led_on aon out");
+        return;
+    }
+    
+    sc->lmc_miireg16 &= ~led;
+    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+    lmc_trace(sc->lmc_device, "lmc_led_on out");
+}
+
+void lmc_led_off(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_led_off in");
+    if(sc->lmc_miireg16 & led){ /* Already set don't do anything */
+        lmc_trace(sc->lmc_device, "lmc_led_off aoff out");
+        return;
+    }
+    
+    sc->lmc_miireg16 |= led;
+    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+    lmc_trace(sc->lmc_device, "lmc_led_off out");
+}
+
+static void lmc_reset(lmc_softc_t * const sc) /*fold00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_reset in");
+    sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
+    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+    sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
+    lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+    /*
+     * make some of the GPIO pins be outputs
+     */
+    lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
+
+    /*
+     * RESET low to force state reset.  This also forces
+     * the transmitter clock to be internal, but we expect to reset
+     * that later anyway.
+     */
+    sc->lmc_gpio &= ~(LMC_GEP_RESET);
+    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+    /*
+     * hold for more than 10 microseconds
+     */
+    udelay(50);
+
+    /*
+     * stop driving Xilinx-related signals
+     */
+    lmc_gpio_mkinput(sc, LMC_GEP_RESET);
+
+    /*
+     * Call media specific init routine
+     */
+    sc->lmc_media->init(sc);
+
+    sc->stats.resetCount++;
+    lmc_trace(sc->lmc_device, "lmc_reset out");
+}
+
+static void lmc_dec_reset(lmc_softc_t * const sc) /*fold00*/
+{
+    u_int32_t val;
+    lmc_trace(sc->lmc_device, "lmc_dec_reset in");
+
+    /*
+     * disable all interrupts
+     */
+    sc->lmc_intrmask = 0;
+    LMC_CSR_WRITE(sc, csr_intr, sc->lmc_intrmask);
+
+    /*
+     * Reset the chip with a software reset command.
+     * Wait 10 microseconds (actually 50 PCI cycles but at
+     * 33MHz that comes to two microseconds but wait a
+     * bit longer anyways)
+     */
+    LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+    udelay(25);
+#ifdef __sparc__
+    sc->lmc_busmode = LMC_CSR_READ(sc, csr_busmode);
+    sc->lmc_busmode = 0x00100000;
+    sc->lmc_busmode &= ~TULIP_BUSMODE_SWRESET;
+    LMC_CSR_WRITE(sc, csr_busmode, sc->lmc_busmode);
+#endif
+    sc->lmc_cmdmode = LMC_CSR_READ(sc, csr_command);
+
+    /*
+     * We want:
+     *   no ethernet address in frames we write
+     *   disable padding (txdesc, padding disable)
+     *   ignore runt frames (rdes0 bit 15)
+     *   no receiver watchdog or transmitter jabber timer
+     *       (csr15 bit 0,14 == 1)
+     *   if using 16-bit CRC, turn off CRC (trans desc, crc disable)
+     */
+
+    sc->lmc_cmdmode |= ( TULIP_CMD_PROMISCUOUS
+                         | TULIP_CMD_FULLDUPLEX
+                         | TULIP_CMD_PASSBADPKT
+                         | TULIP_CMD_NOHEARTBEAT
+                         | TULIP_CMD_PORTSELECT
+                         | TULIP_CMD_RECEIVEALL
+                         | TULIP_CMD_MUSTBEONE
+                       );
+    sc->lmc_cmdmode &= ~( TULIP_CMD_OPERMODE
+                          | TULIP_CMD_THRESHOLDCTL
+                          | TULIP_CMD_STOREFWD
+                          | TULIP_CMD_TXTHRSHLDCTL
+                        );
+
+    LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
+
+    /*
+     * disable receiver watchdog and transmit jabber
+     */
+    val = LMC_CSR_READ(sc, csr_sia_general);
+    val |= (TULIP_WATCHDOG_TXDISABLE | TULIP_WATCHDOG_RXDISABLE);
+    LMC_CSR_WRITE(sc, csr_sia_general, val);
+
+    lmc_trace(sc->lmc_device, "lmc_dec_reset out");
+}
+
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, /*fold00*/
+                         size_t csr_size)
+{
+    lmc_trace(sc->lmc_device, "lmc_initcsrs in");
+    sc->lmc_csrs.csr_busmode	        = csr_base +  0 * csr_size;
+    sc->lmc_csrs.csr_txpoll		= csr_base +  1 * csr_size;
+    sc->lmc_csrs.csr_rxpoll		= csr_base +  2 * csr_size;
+    sc->lmc_csrs.csr_rxlist		= csr_base +  3 * csr_size;
+    sc->lmc_csrs.csr_txlist		= csr_base +  4 * csr_size;
+    sc->lmc_csrs.csr_status		= csr_base +  5 * csr_size;
+    sc->lmc_csrs.csr_command	        = csr_base +  6 * csr_size;
+    sc->lmc_csrs.csr_intr		= csr_base +  7 * csr_size;
+    sc->lmc_csrs.csr_missed_frames	= csr_base +  8 * csr_size;
+    sc->lmc_csrs.csr_9		        = csr_base +  9 * csr_size;
+    sc->lmc_csrs.csr_10		        = csr_base + 10 * csr_size;
+    sc->lmc_csrs.csr_11		        = csr_base + 11 * csr_size;
+    sc->lmc_csrs.csr_12		        = csr_base + 12 * csr_size;
+    sc->lmc_csrs.csr_13		        = csr_base + 13 * csr_size;
+    sc->lmc_csrs.csr_14		        = csr_base + 14 * csr_size;
+    sc->lmc_csrs.csr_15		        = csr_base + 15 * csr_size;
+    lmc_trace(sc->lmc_device, "lmc_initcsrs out");
+}
+
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/
+    lmc_softc_t *sc;
+    u32 csr6;
+    LMC_SPIN_FLAGS;
+
+    lmc_trace(dev, "lmc_driver_timeout in");
+
+    sc = dev->priv;
+
+    spin_lock_irqsave(&sc->lmc_lock, flags);
+
+    printk("%s: Xmitter busy|\n", dev->name);
+
+    sc->stats.tx_tbusy_calls++ ;
+    if (jiffies - dev->trans_start < TX_TIMEOUT) {
+        goto bug_out;
+    }
+
+    /*
+     * Chip seems to have locked up
+     * Reset it
+     * This whips out all our decriptor
+     * table and starts from scartch
+     */
+
+    LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO,
+                  LMC_CSR_READ (sc, csr_status),
+                  sc->stats.tx_ProcTimeout);
+
+    lmc_running_reset (dev);
+
+    LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+    LMC_EVENT_LOG(LMC_EVENT_RESET2,
+                  lmc_mii_readreg (sc, 0, 16),
+                  lmc_mii_readreg (sc, 0, 17));
+
+    /* restart the tx processes */
+    csr6 = LMC_CSR_READ (sc, csr_command);
+    LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002);
+    LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002);
+
+    /* immediate transmit */
+    LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+    sc->stats.tx_errors++;
+    sc->stats.tx_ProcTimeout++;	/* -baz */
+
+    dev->trans_start = jiffies;
+
+bug_out:
+
+    spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+    lmc_trace(dev, "lmc_driver_timout out");
+
+
+}
+
+int lmc_setup(void) { /*FOLD00*/
+   return lmc_probe(NULL);
+}
+
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.c linux/drivers/net/wan/lmc/lmc_media.c
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_media.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,1258 @@
+/* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/segment.h>
+//#include <asm/smp.h>
+
+#if LINUX_VERSION_CODE < 0x20155
+#include <linux/bios32.h>
+#endif
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h>             /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+
+#if LINUX_VERSION_CODE >= 0x20200
+#include <asm/uaccess.h>
+//#include <asm/spinlock.h>
+#endif
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_ioctl.h"
+#include "lmc_debug.h"
+
+#define CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE 1
+
+ /*
+  * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+  * All rights reserved.  www.lanmedia.com
+  *
+  * This code is written by:
+  * Andrew Stanley-Jones (asj@cban.com)
+  * Rob Braun (bbraun@vix.com),
+  * Michael Graff (explorer@vix.com) and
+  * Matt Thomas (matt@3am-software.com).
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU Public License version 2, incorporated herein by reference.
+  */
+
+/*
+ * For lack of a better place, put the SSI cable stuff here.
+ */
+char *lmc_t1_cables[] = {
+  "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35",
+  "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL
+};
+
+/*
+ * protocol independent method.
+ */
+static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *);
+
+/*
+ * media independent methods to check on media status, link, light LEDs,
+ * etc.
+ */
+static void lmc_ds3_init (lmc_softc_t * const);
+static void lmc_ds3_default (lmc_softc_t * const);
+static void lmc_ds3_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_ds3_set_100ft (lmc_softc_t * const, int);
+static int lmc_ds3_get_link_status (lmc_softc_t * const);
+static void lmc_ds3_set_crc_length (lmc_softc_t * const, int);
+static void lmc_ds3_set_scram (lmc_softc_t * const, int);
+static void lmc_ds3_watchdog (lmc_softc_t * const);
+
+static void lmc_hssi_init (lmc_softc_t * const);
+static void lmc_hssi_default (lmc_softc_t * const);
+static void lmc_hssi_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_hssi_set_clock (lmc_softc_t * const, int);
+static int lmc_hssi_get_link_status (lmc_softc_t * const);
+static void lmc_hssi_set_link_status (lmc_softc_t * const, int);
+static void lmc_hssi_set_crc_length (lmc_softc_t * const, int);
+static void lmc_hssi_watchdog (lmc_softc_t * const);
+
+static void lmc_ssi_init (lmc_softc_t * const);
+static void lmc_ssi_default (lmc_softc_t * const);
+static void lmc_ssi_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_ssi_set_clock (lmc_softc_t * const, int);
+static void lmc_ssi_set_speed (lmc_softc_t * const, lmc_ctl_t *);
+static int lmc_ssi_get_link_status (lmc_softc_t * const);
+static void lmc_ssi_set_link_status (lmc_softc_t * const, int);
+static void lmc_ssi_set_crc_length (lmc_softc_t * const, int);
+static void lmc_ssi_watchdog (lmc_softc_t * const);
+
+static void lmc_t1_init (lmc_softc_t * const);
+static void lmc_t1_default (lmc_softc_t * const);
+static void lmc_t1_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static int lmc_t1_get_link_status (lmc_softc_t * const);
+static void lmc_t1_set_circuit_type (lmc_softc_t * const, int);
+static void lmc_t1_set_crc_length (lmc_softc_t * const, int);
+static void lmc_t1_set_clock (lmc_softc_t * const, int);
+static void lmc_t1_watchdog (lmc_softc_t * const);
+
+static void lmc_dummy_set_1 (lmc_softc_t * const, int);
+static void lmc_dummy_set2_1 (lmc_softc_t * const, lmc_ctl_t *);
+
+static inline void write_av9110_bit (lmc_softc_t *, int);
+static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t,
+			  u_int32_t, u_int32_t);
+
+lmc_media_t lmc_ds3_media = {
+  lmc_ds3_init,			/* special media init stuff */
+  lmc_ds3_default,		/* reset to default state */
+  lmc_ds3_set_status,		/* reset status to state provided */
+  lmc_dummy_set_1,		/* set clock source */
+  lmc_dummy_set2_1,		/* set line speed */
+  lmc_ds3_set_100ft,		/* set cable length */
+  lmc_ds3_set_scram,		/* set scrambler */
+  lmc_ds3_get_link_status,	/* get link status */
+  lmc_dummy_set_1,		/* set link status */
+  lmc_ds3_set_crc_length,	/* set CRC length */
+  lmc_dummy_set_1,		/* set T1 or E1 circuit type */
+  lmc_ds3_watchdog
+};
+
+lmc_media_t lmc_hssi_media = {
+  lmc_hssi_init,		/* special media init stuff */
+  lmc_hssi_default,		/* reset to default state */
+  lmc_hssi_set_status,		/* reset status to state provided */
+  lmc_hssi_set_clock,		/* set clock source */
+  lmc_dummy_set2_1,		/* set line speed */
+  lmc_dummy_set_1,		/* set cable length */
+  lmc_dummy_set_1,		/* set scrambler */
+  lmc_hssi_get_link_status,	/* get link status */
+  lmc_hssi_set_link_status,	/* set link status */
+  lmc_hssi_set_crc_length,	/* set CRC length */
+  lmc_dummy_set_1,		/* set T1 or E1 circuit type */
+  lmc_hssi_watchdog
+};
+
+lmc_media_t lmc_ssi_media = { lmc_ssi_init,	/* special media init stuff */
+  lmc_ssi_default,		/* reset to default state */
+  lmc_ssi_set_status,		/* reset status to state provided */
+  lmc_ssi_set_clock,		/* set clock source */
+  lmc_ssi_set_speed,		/* set line speed */
+  lmc_dummy_set_1,		/* set cable length */
+  lmc_dummy_set_1,		/* set scrambler */
+  lmc_ssi_get_link_status,	/* get link status */
+  lmc_ssi_set_link_status,	/* set link status */
+  lmc_ssi_set_crc_length,	/* set CRC length */
+  lmc_dummy_set_1,		/* set T1 or E1 circuit type */
+  lmc_ssi_watchdog
+};
+
+lmc_media_t lmc_t1_media = {
+  lmc_t1_init,			/* special media init stuff */
+  lmc_t1_default,		/* reset to default state */
+  lmc_t1_set_status,		/* reset status to state provided */
+  lmc_t1_set_clock,		/* set clock source */
+  lmc_dummy_set2_1,		/* set line speed */
+  lmc_dummy_set_1,		/* set cable length */
+  lmc_dummy_set_1,		/* set scrambler */
+  lmc_t1_get_link_status,	/* get link status */
+  lmc_dummy_set_1,		/* set link status */
+  lmc_t1_set_crc_length,	/* set CRC length */
+  lmc_t1_set_circuit_type,	/* set T1 or E1 circuit type */
+  lmc_t1_watchdog
+};
+
+static void
+lmc_dummy_set_1 (lmc_softc_t * const sc, int a)
+{
+}
+
+static void
+lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a)
+{
+}
+
+/*
+ *  HSSI methods
+ */
+
+static void
+lmc_hssi_init (lmc_softc_t * const sc)
+{
+  sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5200;
+
+  lmc_gpio_mkoutput (sc, LMC_GEP_HSSI_CLOCK);
+}
+
+static void
+lmc_hssi_default (lmc_softc_t * const sc)
+{
+  sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+  sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+  sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+  sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it.  This will
+ * always reset the card if needed.
+ */
+static void
+lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+  if (ctl == NULL)
+    {
+      sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source);
+      lmc_set_protocol (sc, NULL);
+
+      return;
+    }
+
+  /*
+   * check for change in clock source
+   */
+  if (ctl->clock_source && !sc->ictl.clock_source)
+    {
+      sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT);
+      sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT;
+    }
+  else if (!ctl->clock_source && sc->ictl.clock_source)
+    {
+      sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+      sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+    }
+
+  lmc_set_protocol (sc, ctl);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_hssi_set_clock (lmc_softc_t * const sc, int ie)
+{
+  int old;
+  old = sc->ictl.clock_source;
+  if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+    {
+      sc->lmc_gpio |= LMC_GEP_HSSI_CLOCK;
+      LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+      sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+      if(old != ie)
+        printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+    }
+  else
+    {
+      sc->lmc_gpio &= ~(LMC_GEP_HSSI_CLOCK);
+      LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+      sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+      if(old != ie)
+        printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+    }
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_hssi_get_link_status (lmc_softc_t * const sc)
+{
+    /*
+     * We're using the same code as SSI since
+     * they're practically the same
+     */
+    return lmc_ssi_get_link_status(sc);
+}
+
+static void
+lmc_hssi_set_link_status (lmc_softc_t * const sc, int state)
+{
+  if (state == LMC_LINK_UP)
+    sc->lmc_miireg16 |= LMC_MII16_HSSI_TA;
+  else
+    sc->lmc_miireg16 &= ~LMC_MII16_HSSI_TA;
+
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state)
+{
+  if (state == LMC_CTL_CRC_LENGTH_32)
+    {
+      /* 32 bit */
+      sc->lmc_miireg16 |= LMC_MII16_HSSI_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+    }
+  else
+    {
+      /* 16 bit */
+      sc->lmc_miireg16 &= ~LMC_MII16_HSSI_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+    }
+
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_hssi_watchdog (lmc_softc_t * const sc)
+{
+  /* HSSI is blank */
+}
+
+/*
+ *  DS3 methods
+ */
+
+/*
+ * Set cable length
+ */
+static void
+lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie)
+{
+  if (ie == LMC_CTL_CABLE_LENGTH_GT_100FT)
+    {
+      sc->lmc_miireg16 &= ~LMC_MII16_DS3_ZERO;
+      sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_GT_100FT;
+    }
+  else if (ie == LMC_CTL_CABLE_LENGTH_LT_100FT)
+    {
+      sc->lmc_miireg16 |= LMC_MII16_DS3_ZERO;
+      sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_LT_100FT;
+    }
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_ds3_default (lmc_softc_t * const sc)
+{
+  sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+  sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+  sc->lmc_media->set_cable_length (sc, LMC_CTL_CABLE_LENGTH_LT_100FT);
+  sc->lmc_media->set_scrambler (sc, LMC_CTL_OFF);
+  sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it.  This will
+ * always reset the card if needed.
+ */
+static void
+lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+  if (ctl == NULL)
+    {
+      sc->lmc_media->set_cable_length (sc, sc->ictl.cable_length);
+      sc->lmc_media->set_scrambler (sc, sc->ictl.scrambler_onoff);
+      lmc_set_protocol (sc, NULL);
+
+      return;
+    }
+
+  /*
+   * check for change in cable length setting
+   */
+  if (ctl->cable_length && !sc->ictl.cable_length)
+    lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_GT_100FT);
+  else if (!ctl->cable_length && sc->ictl.cable_length)
+    lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_LT_100FT);
+
+  /*
+   * Check for change in scrambler setting (requires reset)
+   */
+  if (ctl->scrambler_onoff && !sc->ictl.scrambler_onoff)
+    lmc_ds3_set_scram (sc, LMC_CTL_ON);
+  else if (!ctl->scrambler_onoff && sc->ictl.scrambler_onoff)
+    lmc_ds3_set_scram (sc, LMC_CTL_OFF);
+
+  lmc_set_protocol (sc, ctl);
+}
+
+static void
+lmc_ds3_init (lmc_softc_t * const sc)
+{
+  int i;
+
+  sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5245;
+
+  /* writes zeros everywhere */
+  for (i = 0; i < 21; i++)
+    {
+      lmc_mii_writereg (sc, 0, 17, i);
+      lmc_mii_writereg (sc, 0, 18, 0);
+    }
+
+  /* set some essential bits */
+  lmc_mii_writereg (sc, 0, 17, 1);
+  lmc_mii_writereg (sc, 0, 18, 0x25);	/* ser, xtx */
+
+  lmc_mii_writereg (sc, 0, 17, 5);
+  lmc_mii_writereg (sc, 0, 18, 0x80);	/* emode */
+
+  lmc_mii_writereg (sc, 0, 17, 14);
+  lmc_mii_writereg (sc, 0, 18, 0x30);	/* rcgen, tcgen */
+
+  /* clear counters and latched bits */
+  for (i = 0; i < 21; i++)
+    {
+      lmc_mii_writereg (sc, 0, 17, i);
+      lmc_mii_readreg (sc, 0, 18);
+    }
+}
+
+/*
+ * 1 == DS3 payload scrambled, 0 == not scrambled
+ */
+static void
+lmc_ds3_set_scram (lmc_softc_t * const sc, int ie)
+{
+  if (ie == LMC_CTL_ON)
+    {
+      sc->lmc_miireg16 |= LMC_MII16_DS3_SCRAM;
+      sc->ictl.scrambler_onoff = LMC_CTL_ON;
+    }
+  else
+    {
+      sc->lmc_miireg16 &= ~LMC_MII16_DS3_SCRAM;
+      sc->ictl.scrambler_onoff = LMC_CTL_OFF;
+    }
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_ds3_get_link_status (lmc_softc_t * const sc)
+{
+    u_int16_t link_status, link_status_11;
+    int ret = 1;
+
+    lmc_mii_writereg (sc, 0, 17, 7);
+    link_status = lmc_mii_readreg (sc, 0, 18);
+
+    /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions
+     * led0 yellow = far-end adapter is in Red alarm condition
+     * led1 blue   = received an Alarm Indication signal
+     *               (upstream failure)
+     * led2 Green  = power to adapter, Gate Array loaded & driver
+     *               attached
+     * led3 red    = Loss of Signal (LOS) or out of frame (OOF)
+     *               conditions detected on T3 receive signal
+     */
+
+    lmc_led_on(sc, LMC_DS3_LED2);
+
+    if ((link_status & LMC_FRAMER_REG0_DLOS) ||
+        (link_status & LMC_FRAMER_REG0_OOFS)){
+        ret = 0;
+        if(sc->last_led_err[3] != 1){
+            u16 r1;
+            lmc_mii_writereg (sc, 0, 17, 01); /* Turn on Xbit error as our cisco does */
+            r1 = lmc_mii_readreg (sc, 0, 18);
+            r1 &= 0xfe;
+            lmc_mii_writereg(sc, 0, 18, r1);
+            printk(KERN_WARNING "%s: Red Alarm - Loss of Signal or Loss of Framing\n", sc->name);
+        }
+        lmc_led_on(sc, LMC_DS3_LED3);	/* turn on red LED */
+        sc->last_led_err[3] = 1;
+    }
+    else {
+        lmc_led_off(sc, LMC_DS3_LED3);	/* turn on red LED */
+        if(sc->last_led_err[3] == 1){
+            u16 r1;
+            lmc_mii_writereg (sc, 0, 17, 01); /* Turn off Xbit error */
+            r1 = lmc_mii_readreg (sc, 0, 18);
+            r1 |= 0x01;
+            lmc_mii_writereg(sc, 0, 18, r1);
+        }
+        sc->last_led_err[3] = 0;
+    }
+
+    lmc_mii_writereg(sc, 0, 17, 0x10);
+    link_status_11 = lmc_mii_readreg(sc, 0, 18);
+    if((link_status & LMC_FRAMER_REG0_AIS) ||
+       (link_status_11 & LMC_FRAMER_REG10_XBIT)) {
+        ret = 0;
+        if(sc->last_led_err[0] != 1){
+            printk(KERN_WARNING "%s: AIS Alarm or XBit Error\n", sc->name);
+            printk(KERN_WARNING "%s: Remote end has loss of signal or framing\n", sc->name);
+        }
+        lmc_led_on(sc, LMC_DS3_LED0);
+        sc->last_led_err[0] = 1;
+    }
+    else {
+        lmc_led_off(sc, LMC_DS3_LED0);
+        sc->last_led_err[0] = 0;
+    }
+
+    lmc_mii_writereg (sc, 0, 17, 9);
+    link_status = lmc_mii_readreg (sc, 0, 18);
+    
+    if(link_status & LMC_FRAMER_REG9_RBLUE){
+        ret = 0;
+        if(sc->last_led_err[1] != 1){
+            printk(KERN_WARNING "%s: Blue Alarm - Receiving all 1's\n", sc->name);
+        }
+        lmc_led_on(sc, LMC_DS3_LED1);
+        sc->last_led_err[1] = 1;
+    }
+    else {
+        lmc_led_off(sc, LMC_DS3_LED1);
+        sc->last_led_err[1] = 0;
+    }
+
+    return ret;
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state)
+{
+  if (state == LMC_CTL_CRC_LENGTH_32)
+    {
+      /* 32 bit */
+      sc->lmc_miireg16 |= LMC_MII16_DS3_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+    }
+  else
+    {
+      /* 16 bit */
+      sc->lmc_miireg16 &= ~LMC_MII16_DS3_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+    }
+
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_ds3_watchdog (lmc_softc_t * const sc)
+{
+    
+}
+
+
+/*
+ *  SSI methods
+ */
+
+static void
+lmc_ssi_init (lmc_softc_t * const sc)
+{
+  u_int16_t mii17;
+  int cable;
+
+  sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1000;
+
+  mii17 = lmc_mii_readreg (sc, 0, 17);
+
+  cable = (mii17 & LMC_MII17_SSI_CABLE_MASK) >> LMC_MII17_SSI_CABLE_SHIFT;
+  sc->ictl.cable_type = cable;
+
+  lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK);
+}
+
+static void
+lmc_ssi_default (lmc_softc_t * const sc)
+{
+  sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+  /*
+   * make TXCLOCK always be an output
+   */
+  lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK);
+
+  sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+  sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+  sc->lmc_media->set_speed (sc, NULL);
+  sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it.  This will
+ * always reset the card if needed.
+ */
+static void
+lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+  if (ctl == NULL)
+    {
+      sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source);
+      sc->lmc_media->set_speed (sc, &sc->ictl);
+      lmc_set_protocol (sc, NULL);
+
+      return;
+    }
+
+  /*
+   * check for change in clock source
+   */
+  if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_INT
+      && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_EXT)
+    {
+      sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT);
+      sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT;
+    }
+  else if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_EXT
+	   && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_INT)
+    {
+      sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+      sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+    }
+
+  if (ctl->clock_rate != sc->ictl.clock_rate)
+    sc->lmc_media->set_speed (sc, ctl);
+
+  lmc_set_protocol (sc, ctl);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_ssi_set_clock (lmc_softc_t * const sc, int ie)
+{
+  int old;
+  old = ie;
+  if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+    {
+      sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
+      LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+      sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+      if(ie != old)
+        printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+    }
+  else
+    {
+      sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
+      LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+      sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+      if(ie != old)
+        printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+    }
+}
+
+static void
+lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+  lmc_ctl_t *ictl = &sc->ictl;
+  lmc_av9110_t *av;
+
+  /* original settings for clock rate of:
+   *  100 Khz (8,25,0,0,2) were incorrect
+   *  they should have been 80,125,1,3,3
+   *  There are 17 param combinations to produce this freq.
+   *  For 1.5 Mhz use 120,100,1,1,2 (226 param. combinations)
+   */
+  if (ctl == NULL)
+    {
+      av = &ictl->cardspec.ssi;
+      ictl->clock_rate = 1500000;
+      av->f = ictl->clock_rate;
+      av->n = 120;
+      av->m = 100;
+      av->v = 1;
+      av->x = 1;
+      av->r = 2;
+
+      write_av9110 (sc, av->n, av->m, av->v, av->x, av->r);
+      return;
+    }
+
+  av = &ctl->cardspec.ssi;
+
+  if (av->f == 0)
+    return;
+
+  ictl->clock_rate = av->f;	/* really, this is the rate we are */
+  ictl->cardspec.ssi = *av;
+
+  write_av9110 (sc, av->n, av->m, av->v, av->x, av->r);
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_ssi_get_link_status (lmc_softc_t * const sc)
+{
+  u_int16_t link_status;
+  u_int32_t ticks;
+  int ret = 1;
+  int hw_hdsk = 1;
+  
+  /*
+   * missing CTS?  Hmm.  If we require CTS on, we may never get the
+   * link to come up, so omit it in this test.
+   *
+   * Also, it seems that with a loopback cable, DCD isn't asserted,
+   * so just check for things like this:
+   *      DSR _must_ be asserted.
+   *      One of DCD or CTS must be asserted.
+   */
+
+  /* LMC 1000 (SSI) LED definitions
+   * led0 Green = power to adapter, Gate Array loaded &
+   *              driver attached
+   * led1 Green = DSR and DTR and RTS and CTS are set
+   * led2 Green = Cable detected
+   * led3 red   = No timing is available from the
+   *              cable or the on-board frequency
+   *              generator.
+   */
+
+  link_status = lmc_mii_readreg (sc, 0, 16);
+
+  /* Is the transmit clock still available */
+  ticks = LMC_CSR_READ (sc, csr_gp_timer);
+  ticks = 0x0000ffff - (ticks & 0x0000ffff);
+
+  lmc_led_on (sc, LMC_MII16_LED0);
+
+  /* ====== transmit clock determination ===== */
+  if (sc->lmc_timing == LMC_CTL_CLOCK_SOURCE_INT) {
+      lmc_led_off(sc, LMC_MII16_LED3);
+  }
+  else if (ticks == 0 ) {				/* no clock found ? */
+      ret = 0;
+      if(sc->last_led_err[3] != 1){
+          sc->stats.tx_lossOfClockCnt++;
+          printk(KERN_WARNING "%s: Lost Clock, Link Down\n", sc->name);
+      }
+      sc->last_led_err[3] = 1;
+      lmc_led_on (sc, LMC_MII16_LED3);	/* turn ON red LED */
+  }
+  else {
+      if(sc->last_led_err[3] == 1)
+          printk(KERN_WARNING "%s: Clock Returned\n", sc->name);
+      sc->last_led_err[3] = 0;
+      lmc_led_off (sc, LMC_MII16_LED3);		/* turn OFF red LED */
+  }
+
+  if ((link_status & LMC_MII16_SSI_DSR) == 0) { /* Also HSSI CA */
+      ret = 0;
+      hw_hdsk = 0;
+  }
+
+#ifdef CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE
+  if ((link_status & (LMC_MII16_SSI_CTS | LMC_MII16_SSI_DCD)) == 0){
+      ret = 0;
+      hw_hdsk = 0;
+  }
+#endif
+
+  if(hw_hdsk == 0){
+      if(sc->last_led_err[1] != 1)
+          printk(KERN_WARNING "%s: DSR not asserted\n", sc->name);
+      sc->last_led_err[1] = 1;
+      lmc_led_off(sc, LMC_MII16_LED1);
+  }
+  else {
+      if(sc->last_led_err[1] != 0)
+          printk(KERN_WARNING "%s: DSR now asserted\n", sc->name);
+      sc->last_led_err[1] = 0;
+      lmc_led_on(sc, LMC_MII16_LED1);
+  }
+
+  if(ret == 1) {
+      lmc_led_on(sc, LMC_MII16_LED2); /* Over all good status? */
+  }
+  
+  return ret;
+}
+
+static void
+lmc_ssi_set_link_status (lmc_softc_t * const sc, int state)
+{
+  if (state == LMC_LINK_UP)
+    {
+      sc->lmc_miireg16 |= (LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
+      printk (LMC_PRINTF_FMT ": asserting DTR and RTS\n", LMC_PRINTF_ARGS);
+    }
+  else
+    {
+      sc->lmc_miireg16 &= ~(LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
+      printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS);
+    }
+
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state)
+{
+  if (state == LMC_CTL_CRC_LENGTH_32)
+    {
+      /* 32 bit */
+      sc->lmc_miireg16 |= LMC_MII16_SSI_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+      sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
+
+    }
+  else
+    {
+      /* 16 bit */
+      sc->lmc_miireg16 &= ~LMC_MII16_SSI_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+      sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
+    }
+
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * These are bits to program the ssi frequency generator
+ */
+static inline void
+write_av9110_bit (lmc_softc_t * sc, int c)
+{
+  /*
+   * set the data bit as we need it.
+   */
+  sc->lmc_gpio &= ~(LMC_GEP_CLK);
+  if (c & 0x01)
+    sc->lmc_gpio |= LMC_GEP_DATA;
+  else
+    sc->lmc_gpio &= ~(LMC_GEP_DATA);
+  LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+  /*
+   * set the clock to high
+   */
+  sc->lmc_gpio |= LMC_GEP_CLK;
+  LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+  /*
+   * set the clock to low again.
+   */
+  sc->lmc_gpio &= ~(LMC_GEP_CLK);
+  LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+}
+
+static void
+write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v,
+	      u_int32_t x, u_int32_t r)
+{
+  int i;
+
+#if 0
+  printk (LMC_PRINTF_FMT ": speed %u, %d %d %d %d %d\n",
+	  LMC_PRINTF_ARGS, sc->ictl.clock_rate, n, m, v, x, r);
+#endif
+
+  sc->lmc_gpio |= LMC_GEP_SSI_GENERATOR;
+  sc->lmc_gpio &= ~(LMC_GEP_DATA | LMC_GEP_CLK);
+  LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+  /*
+   * Set the TXCLOCK, GENERATOR, SERIAL, and SERIALCLK
+   * as outputs.
+   */
+  lmc_gpio_mkoutput (sc, (LMC_GEP_DATA | LMC_GEP_CLK
+			  | LMC_GEP_SSI_GENERATOR));
+
+  sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR);
+  LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+  /*
+   * a shifting we will go...
+   */
+  for (i = 0; i < 7; i++)
+    write_av9110_bit (sc, n >> i);
+  for (i = 0; i < 7; i++)
+    write_av9110_bit (sc, m >> i);
+  for (i = 0; i < 1; i++)
+    write_av9110_bit (sc, v >> i);
+  for (i = 0; i < 2; i++)
+    write_av9110_bit (sc, x >> i);
+  for (i = 0; i < 2; i++)
+    write_av9110_bit (sc, r >> i);
+  for (i = 0; i < 5; i++)
+    write_av9110_bit (sc, 0x17 >> i);
+
+  /*
+   * stop driving serial-related signals
+   */
+  lmc_gpio_mkinput (sc,
+		    (LMC_GEP_DATA | LMC_GEP_CLK
+		     | LMC_GEP_SSI_GENERATOR));
+}
+
+static void
+lmc_ssi_watchdog (lmc_softc_t * const sc)
+{
+  u_int16_t mii17;
+  struct ssicsr2
+  {
+    unsigned short dtr:1, dsr:1, rts:1, cable:3, crc:1, led0:1, led1:1,
+      led2:1, led3:1, fifo:1, ll:1, rl:1, tm:1, loop:1;
+  };
+  struct ssicsr2 *ssicsr;
+  mii17 = lmc_mii_readreg (sc, 0, 17);
+  ssicsr = (struct ssicsr2 *) &mii17;
+  if (ssicsr->cable == 7)
+    {
+      lmc_led_off (sc, LMC_MII16_LED2);
+    }
+  else
+    {
+      lmc_led_on (sc, LMC_MII16_LED2);
+    }
+
+}
+
+/*
+ *  T1 methods
+ */
+
+/*
+ * The framer regs are multiplexed through MII regs 17 & 18
+ *  write the register address to MII reg 17 and the *  data to MII reg 18. */
+static void
+lmc_t1_write (lmc_softc_t * const sc, int a, int d)
+{
+  lmc_mii_writereg (sc, 0, 17, a);
+  lmc_mii_writereg (sc, 0, 18, d);
+}
+
+/* Save a warning
+static int
+lmc_t1_read (lmc_softc_t * const sc, int a)
+{
+  lmc_mii_writereg (sc, 0, 17, a);
+  return lmc_mii_readreg (sc, 0, 18);
+}
+*/
+
+
+static void
+lmc_t1_init (lmc_softc_t * const sc)
+{
+  u_int16_t mii16;
+  int i;
+
+  sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1200;
+  mii16 = lmc_mii_readreg (sc, 0, 16);
+
+  /* reset 8370 */
+  mii16 &= ~LMC_MII16_T1_RST;
+  lmc_mii_writereg (sc, 0, 16, mii16 | LMC_MII16_T1_RST);
+  lmc_mii_writereg (sc, 0, 16, mii16);
+
+  /* set T1 or E1 line.  Uses sc->lmcmii16 reg in function so update it */
+  sc->lmc_miireg16 = mii16;
+  lmc_t1_set_circuit_type(sc, LMC_CTL_CIRCUIT_TYPE_T1);
+  mii16 = sc->lmc_miireg16;
+
+  lmc_t1_write (sc, 0x01, 0x1B);	/* CR0     - primary control             */
+  lmc_t1_write (sc, 0x02, 0x42);	/* JAT_CR  - jitter atten config         */
+  lmc_t1_write (sc, 0x14, 0x00);	/* LOOP    - loopback config             */
+  lmc_t1_write (sc, 0x15, 0x00);	/* DL3_TS  - external data link timeslot */
+  lmc_t1_write (sc, 0x18, 0xFF);	/* PIO     - programmable I/O            */
+  lmc_t1_write (sc, 0x19, 0x30);	/* POE     - programmable OE             */
+  lmc_t1_write (sc, 0x1A, 0x0F);	/* CMUX    - clock input mux             */
+  lmc_t1_write (sc, 0x20, 0x41);	/* LIU_CR  - RX LIU config               */
+  lmc_t1_write (sc, 0x22, 0x76);	/* RLIU_CR - RX LIU config               */
+  lmc_t1_write (sc, 0x40, 0x03);	/* RCR0    - RX config                   */
+  lmc_t1_write (sc, 0x45, 0x00);	/* RALM    - RX alarm config             */
+  lmc_t1_write (sc, 0x46, 0x05);	/* LATCH   - RX alarm/err/cntr latch     */
+  lmc_t1_write (sc, 0x68, 0x40);	/* TLIU_CR - TX LIU config               */
+  lmc_t1_write (sc, 0x70, 0x0D);	/* TCR0    - TX framer config            */
+  lmc_t1_write (sc, 0x71, 0x05);	/* TCR1    - TX config                   */
+  lmc_t1_write (sc, 0x72, 0x0B);	/* TFRM    - TX frame format             */
+  lmc_t1_write (sc, 0x73, 0x00);	/* TERROR  - TX error insert             */
+  lmc_t1_write (sc, 0x74, 0x00);	/* TMAN    - TX manual Sa/FEBE config    */
+  lmc_t1_write (sc, 0x75, 0x00);	/* TALM    - TX alarm signal config      */
+  lmc_t1_write (sc, 0x76, 0x00);	/* TPATT   - TX test pattern config      */
+  lmc_t1_write (sc, 0x77, 0x00);	/* TLB     - TX inband loopback config   */
+  lmc_t1_write (sc, 0x90, 0x05);	/* CLAD_CR - clock rate adapter config   */
+  lmc_t1_write (sc, 0x91, 0x05);	/* CSEL    - clad freq sel               */
+  lmc_t1_write (sc, 0xA6, 0x00);	/* DL1_CTL - DL1 control                 */
+  lmc_t1_write (sc, 0xB1, 0x00);	/* DL2_CTL - DL2 control                 */
+  lmc_t1_write (sc, 0xD0, 0x47);	/* SBI_CR  - sys bus iface config        */
+  lmc_t1_write (sc, 0xD1, 0x70);	/* RSB_CR  - RX sys bus config           */
+  lmc_t1_write (sc, 0xD4, 0x30);	/* TSB_CR  - TX sys bus config           */
+  for (i = 0; i < 32; i++)
+    {
+      lmc_t1_write (sc, 0x0E0 + i, 0x00);	/* SBCn - sys bus per-channel ctl    */
+      lmc_t1_write (sc, 0x100 + i, 0x00);	/* TPCn - TX per-channel ctl         */
+      lmc_t1_write (sc, 0x180 + i, 0x00);	/* RPCn - RX per-channel ctl         */
+    }
+  for (i = 1; i < 25; i++)
+    {
+      lmc_t1_write (sc, 0x0E0 + i, 0x0D);	/* SBCn - sys bus per-channel ctl    */
+    }
+
+  mii16 |= LMC_MII16_T1_XOE;
+  lmc_mii_writereg (sc, 0, 16, mii16);
+  sc->lmc_miireg16 = mii16;
+}
+
+static void
+lmc_t1_default (lmc_softc_t * const sc)
+{
+  sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+  sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+  sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1);
+  sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+  /* Right now we can only clock from out internal source */
+  sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+}
+/* * Given a user provided state, set ourselves up to match it.  This will * always reset the card if needed.
+ */
+static void
+lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+  if (ctl == NULL)
+    {
+      sc->lmc_media->set_circuit_type (sc, sc->ictl.circuit_type);
+      lmc_set_protocol (sc, NULL);
+
+      return;
+    }
+  /*
+   * check for change in circuit type         */
+  if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_T1
+      && sc->ictl.circuit_type ==
+      LMC_CTL_CIRCUIT_TYPE_E1) sc->lmc_media->set_circuit_type (sc,
+								LMC_CTL_CIRCUIT_TYPE_E1);
+  else if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_E1
+	   && sc->ictl.circuit_type == LMC_CTL_CIRCUIT_TYPE_T1)
+    sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1);
+  lmc_set_protocol (sc, ctl);
+}
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */ static int
+lmc_t1_get_link_status (lmc_softc_t * const sc)
+{
+    u_int16_t link_status;
+    int ret = 1;
+
+  /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions
+   * led0 yellow = far-end adapter is in Red alarm condition
+   * led1 blue   = received an Alarm Indication signal
+   *               (upstream failure)
+   * led2 Green  = power to adapter, Gate Array loaded & driver
+   *               attached
+   * led3 red    = Loss of Signal (LOS) or out of frame (OOF)
+   *               conditions detected on T3 receive signal
+   */
+    lmc_trace(sc->lmc_device, "lmc_t1_get_link_status in");
+    lmc_led_on(sc, LMC_DS3_LED2);
+
+    lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM1_STATUS);
+    link_status = lmc_mii_readreg (sc, 0, 18);
+
+
+    if (link_status & T1F_RAIS) {			/* turn on blue LED */
+        ret = 0;
+        if(sc->last_led_err[1] != 1){
+            printk(KERN_WARNING "%s: Receive AIS/Blue Alarm. Far end in RED alarm\n", sc->name);
+        }
+        lmc_led_on(sc, LMC_DS3_LED1);
+        sc->last_led_err[1] = 1;
+    }
+    else {
+        if(sc->last_led_err[1] != 0){
+            printk(KERN_WARNING "%s: End AIS/Blue Alarm\n", sc->name);
+        }
+        lmc_led_off (sc, LMC_DS3_LED1);
+        sc->last_led_err[1] = 0;
+    }
+
+    /*
+     * Yellow Alarm is nasty evil stuff, looks at data patterns
+     * inside the channel and confuses it with HDLC framing
+     * ignore all yellow alarms.
+     *
+     * Do listen to MultiFrame Yellow alarm which while implemented
+     * different ways isn't in the channel and hence somewhat
+     * more reliable
+     */
+
+    if (link_status & T1F_RMYEL) {
+        ret = 0;
+        if(sc->last_led_err[0] != 1){
+            printk(KERN_WARNING "%s: Receive Yellow AIS Alarm\n", sc->name);
+        }
+        lmc_led_on(sc, LMC_DS3_LED0);
+        sc->last_led_err[0] = 1;
+    }
+    else {
+        if(sc->last_led_err[0] != 0){
+            printk(KERN_WARNING "%s: End of Yellow AIS Alarm\n", sc->name);
+        }
+        lmc_led_off(sc, LMC_DS3_LED0);
+        sc->last_led_err[0] = 0;
+    }
+
+    /*
+     * Loss of signal and los of frame
+     * Use the green bit to identify which one lit the led
+     */
+    if(link_status & T1F_RLOF){
+        ret = 0;
+        if(sc->last_led_err[3] != 1){
+            printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing\n", sc->name);
+        }
+        lmc_led_on(sc, LMC_DS3_LED3);
+        sc->last_led_err[3] = 1;
+
+    }
+    else {
+        if(sc->last_led_err[3] != 0){
+            printk(KERN_WARNING "%s: End Red Alarm (LOF)\n", sc->name);
+        }
+        if( ! (link_status & T1F_RLOS))
+            lmc_led_off(sc, LMC_DS3_LED3);
+        sc->last_led_err[3] = 0;
+    }
+    
+    if(link_status & T1F_RLOS){
+        ret = 0;
+        if(sc->last_led_err[2] != 1){
+            printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal\n", sc->name);
+        }
+        lmc_led_on(sc, LMC_DS3_LED3);
+        sc->last_led_err[2] = 1;
+
+    }
+    else {
+        if(sc->last_led_err[2] != 0){
+            printk(KERN_WARNING "%s: End Red Alarm (LOS)\n", sc->name);
+        }
+        if( ! (link_status & T1F_RLOF))
+            lmc_led_off(sc, LMC_DS3_LED3);
+        sc->last_led_err[2] = 0;
+    }
+
+    sc->lmc_xinfo.t1_alarm1_status = link_status;
+
+    lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM2_STATUS);
+    sc->lmc_xinfo.t1_alarm2_status = lmc_mii_readreg (sc, 0, 18);
+
+    
+    lmc_trace(sc->lmc_device, "lmc_t1_get_link_status out");
+
+    return ret;
+}
+
+/*
+ * 1 == T1 Circuit Type , 0 == E1 Circuit Type
+ */
+static void
+lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie)
+{
+  if (ie == LMC_CTL_CIRCUIT_TYPE_T1) {
+      sc->lmc_miireg16 |= LMC_MII16_T1_Z;
+      sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_T1;
+      printk(KERN_INFO "%s: In T1 Mode\n", sc->name);
+  }
+  else {
+      sc->lmc_miireg16 &= ~LMC_MII16_T1_Z;
+      sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_E1;
+      printk(KERN_INFO "%s: In E1 Mode\n", sc->name);
+  }
+
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+  
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit */
+static void
+lmc_t1_set_crc_length (lmc_softc_t * const sc, int state)
+{
+  if (state == LMC_CTL_CRC_LENGTH_32)
+    {
+      /* 32 bit */
+      sc->lmc_miireg16 |= LMC_MII16_T1_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+      sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
+
+    }
+  else
+    {
+      /* 16 bit */ sc->lmc_miireg16 &= ~LMC_MII16_T1_CRC;
+      sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+      sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
+
+    }
+
+  lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_t1_set_clock (lmc_softc_t * const sc, int ie)
+{
+  int old;
+  old = ie;
+  if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+    {
+      sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
+      LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+      sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+      if(old != ie)
+        printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+    }
+  else
+    {
+      sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
+      LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+      sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+      if(old != ie)
+        printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+    }
+}
+
+static void
+lmc_t1_watchdog (lmc_softc_t * const sc)
+{
+}
+
+static void
+lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+  if (ctl == 0)
+    {
+      sc->ictl.keepalive_onoff = LMC_CTL_ON;
+
+      return;
+    }
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.h linux/drivers/net/wan/lmc/lmc_media.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_media.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,64 @@
+#ifndef _LMC_MEDIA_H_
+#define _LMC_MEDIA_H_
+
+lmc_media_t lmc_ds3_media = {
+  lmc_ds3_init,			/* special media init stuff */
+  lmc_ds3_default,		/* reset to default state */
+  lmc_ds3_set_status,		/* reset status to state provided */
+  lmc_dummy_set_1,		/* set clock source */
+  lmc_dummy_set2_1,		/* set line speed */
+  lmc_ds3_set_100ft,		/* set cable length */
+  lmc_ds3_set_scram,		/* set scrambler */
+  lmc_ds3_get_link_status,	/* get link status */
+  lmc_dummy_set_1,		/* set link status */
+  lmc_ds3_set_crc_length,	/* set CRC length */
+  lmc_dummy_set_1,		/* set T1 or E1 circuit type */
+  lmc_ds3_watchdog
+};
+
+lmc_media_t lmc_hssi_media = {
+  lmc_hssi_init,		/* special media init stuff */
+  lmc_hssi_default,		/* reset to default state */
+  lmc_hssi_set_status,		/* reset status to state provided */
+  lmc_hssi_set_clock,		/* set clock source */
+  lmc_dummy_set2_1,		/* set line speed */
+  lmc_dummy_set_1,		/* set cable length */
+  lmc_dummy_set_1,		/* set scrambler */
+  lmc_hssi_get_link_status,	/* get link status */
+  lmc_hssi_set_link_status,	/* set link status */
+  lmc_hssi_set_crc_length,	/* set CRC length */
+  lmc_dummy_set_1,		/* set T1 or E1 circuit type */
+  lmc_hssi_watchdog
+};
+
+lmc_media_t lmc_ssi_media = { lmc_ssi_init,	/* special media init stuff */
+  lmc_ssi_default,		/* reset to default state */
+  lmc_ssi_set_status,		/* reset status to state provided */
+  lmc_ssi_set_clock,		/* set clock source */
+  lmc_ssi_set_speed,		/* set line speed */
+  lmc_dummy_set_1,		/* set cable length */
+  lmc_dummy_set_1,		/* set scrambler */
+  lmc_ssi_get_link_status,	/* get link status */
+  lmc_ssi_set_link_status,	/* set link status */
+  lmc_ssi_set_crc_length,	/* set CRC length */
+  lmc_dummy_set_1,		/* set T1 or E1 circuit type */
+  lmc_ssi_watchdog
+};
+
+lmc_media_t lmc_t1_media = {
+  lmc_t1_init,			/* special media init stuff */
+  lmc_t1_default,		/* reset to default state */
+  lmc_t1_set_status,		/* reset status to state provided */
+  lmc_t1_set_clock,		/* set clock source */
+  lmc_dummy_set2_1,		/* set line speed */
+  lmc_dummy_set_1,		/* set cable length */
+  lmc_dummy_set_1,		/* set scrambler */
+  lmc_t1_get_link_status,	/* get link status */
+  lmc_dummy_set_1,		/* set link status */
+  lmc_t1_set_crc_length,	/* set CRC length */
+  lmc_t1_set_circuit_type,	/* set T1 or E1 circuit type */
+  lmc_t1_watchdog
+};
+
+
+#endif
\ No newline at end of file
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_prot.h linux/drivers/net/wan/lmc/lmc_prot.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_prot.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_prot.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,14 @@
+#ifndef _LMC_PROTO_H_
+#define _LMC_PROTO_H_
+
+void lmc_proto_init(lmc_softc_t * const)
+void lmc_proto_attach(lmc_softc_t *sc const)
+void lmc_proto_detach(lmc_softc *sc const)
+void lmc_proto_reopen(lmc_softc_t *sc const)
+int lmc_proto_ioctl(lmc_softc_t *sc const, struct ifreq *ifr, int cmd)
+void lmc_proto_open(lmc_softc_t *sc const)
+void lmc_proto_close(lmc_softc_t *sc const)
+unsigned short lmc_proto_type(lmc_softc_t *sc const, struct skbuff *skb)
+
+
+#endif
\ No newline at end of file
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.c linux/drivers/net/wan/lmc/lmc_proto.c
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_proto.c	Fri Apr 21 16:38:26 2000
@@ -0,0 +1,270 @@
+ /*
+  * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+  * All rights reserved.  www.lanmedia.com
+  *
+  * This code is written by:
+  * Andrew Stanley-Jones (asj@cban.com)
+  * Rob Braun (bbraun@vix.com),
+  * Michael Graff (explorer@vix.com) and
+  * Matt Thomas (matt@3am-software.com).
+  *
+  * With Help By:
+  * David Boggs
+  * Ron Crane
+  * Allan Cox
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU Public License version 2, incorporated herein by reference.
+  *
+  * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+  */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h>             /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_debug.h"
+#include "lmc_ioctl.h"
+#include "lmc_proto.h"
+//#include "lmc_proto_raw.h"
+
+/*
+ * The compile-time variable SPPPSTUP causes the module to be
+ * compiled without referencing any of the sync ppp routines.
+ */
+#ifdef SPPPSTUB
+#define SYNC_PPP_init() (void)0
+#define SPPP_detach(d)	(void)0
+#define SPPP_open(d)	0
+#define SPPP_reopen(d)	(void)0
+#define SPPP_close(d)	(void)0
+#define SPPP_attach(d)	(void)0
+#define SPPP_do_ioctl(d,i,c)	-EOPNOTSUPP
+#else
+#if LINUX_VERSION_CODE < 0x20363
+#define SYNC_PPP_init	sync_ppp_init
+#define SPPP_attach(x)	sppp_attach((struct ppp_device *)(x)->lmc_device)
+#define SPPP_detach(x)	sppp_detach((x)->lmc_device)
+#define SPPP_open(x)	sppp_open((x)->lmc_device)
+#define SPPP_reopen(x)	sppp_reopen((x)->lmc_device)
+#define SPPP_close(x)	sppp_close((x)->lmc_device)
+#define SPPP_do_ioctl(x, y, z)	sppp_do_ioctl((x)->lmc_device, (y), (z))
+#else
+#define SYNC_PPP_init	sync_ppp_init
+#define SPPP_attach(x)	sppp_attach((x)->pd)
+#define SPPP_detach(x)	sppp_detach((x)->pd->dev)
+#define SPPP_open(x)	sppp_open((x)->pd->dev)
+#define SPPP_reopen(x)	sppp_reopen((x)->pd->dev)
+#define SPPP_close(x)	sppp_close((x)->pd->dev)
+#define SPPP_do_ioctl(x, y, z)	sppp_do_ioctl((x)->pd->dev, (y), (z))
+#endif
+#endif
+
+static int lmc_first_ppp_load = 0;
+
+// init
+void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_proto_init in");
+    switch(sc->if_type){
+    case LMC_PPP:
+        if(lmc_first_ppp_load == 0)
+#ifndef MODULE
+            SYNC_PPP_init();
+#endif
+        
+#if LINUX_VERSION_CODE >= 0x20363
+        sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
+        sc->pd->dev = sc->lmc_device;
+#endif
+        sc->if_ptr = sc->pd;
+        break;
+    case LMC_RAW:
+        break;
+    default:
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_init out");
+}
+
+// attach
+void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_proto_attach in");
+    switch(sc->if_type){
+    case LMC_PPP:
+        {
+            struct net_device *dev = sc->lmc_device;
+            SPPP_attach(sc);
+            dev->do_ioctl = lmc_ioctl;
+        }
+        break;
+    case LMC_NET:
+        {
+            struct net_device *dev = sc->lmc_device;
+            /*
+             * They set a few basics because they don't use sync_ppp
+             */
+            dev->flags |= IFF_POINTOPOINT;
+            dev->hard_header = 0;
+            dev->hard_header_len = 0;
+            dev->addr_len = 0;
+        }
+    case LMC_RAW: /* Setup the task queue, maybe we should notify someone? */
+        {
+        }
+    default:
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_attach out");
+}
+
+// detach
+void lmc_proto_detach(lmc_softc_t *sc) /*FOLD00*/
+{
+    switch(sc->if_type){
+    case LMC_PPP:
+        SPPP_detach(sc);
+        break;
+    case LMC_RAW: /* Tell someone we're detaching? */
+        break;
+    default:
+        break;
+    }
+
+}
+
+// reopen
+void lmc_proto_reopen(lmc_softc_t *sc) /*FOLD00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_proto_reopen in");
+    switch(sc->if_type){
+    case LMC_PPP:
+        SPPP_reopen(sc);
+        break;
+    case LMC_RAW: /* Reset the interface after being down, prerape to receive packets again */
+        break;
+    default:
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_reopen out");
+}
+
+
+// ioctl
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd) /*FOLD00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+    switch(sc->if_type){
+    case LMC_PPP:
+        return SPPP_do_ioctl (sc, ifr, cmd);
+        break;
+    default:
+        return -EOPNOTSUPP;
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+}
+
+// open
+void lmc_proto_open(lmc_softc_t *sc) /*FOLD00*/
+{
+    int ret;
+
+    lmc_trace(sc->lmc_device, "lmc_proto_open in");
+    switch(sc->if_type){
+    case LMC_PPP:
+        ret = SPPP_open(sc);
+        if(ret < 0)
+            printk("%s: syncPPP open failed: %d\n", sc->name, ret);
+        break;
+    case LMC_RAW: /* We're about to start getting packets! */
+        break;
+    default:
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_open out");
+}
+
+// close
+
+void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_proto_close in");
+    switch(sc->if_type){
+    case LMC_PPP:
+        SPPP_close(sc);
+        break;
+    case LMC_RAW: /* Interface going down */
+        break;
+    default:
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_close out");
+}
+
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_proto_type in");
+    switch(sc->if_type){
+    case LMC_PPP:
+        return htons(ETH_P_WAN_PPP);
+        break;
+    case LMC_NET:
+        return htons(ETH_P_802_2);
+        break;
+    case LMC_RAW: /* Packet type for skbuff kind of useless */
+        return htons(ETH_P_802_2);
+        break;
+    default:
+        printk(KERN_WARNING "%s: No protocol set for this interface, assuming 802.2 (which is wrong!!)\n", sc->name);
+        return htons(ETH_P_802_2);
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_tye out");
+
+}
+
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+    lmc_trace(sc->lmc_device, "lmc_proto_netif in");
+    switch(sc->if_type){
+    case LMC_PPP:
+    case LMC_NET:
+    default:
+        netif_rx(skb);
+        break;
+    case LMC_RAW:
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_netif out");
+}
+
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.h linux/drivers/net/wan/lmc/lmc_proto.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_proto.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,15 @@
+#ifndef _LMC_PROTO_H_
+#define _LMC_PROTO_H_
+
+void lmc_proto_init(lmc_softc_t *sc);
+void lmc_proto_attach(lmc_softc_t *sc);
+void lmc_proto_detach(lmc_softc_t *sc);
+void lmc_proto_reopen(lmc_softc_t *sc);
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd);
+void lmc_proto_open(lmc_softc_t *sc);
+void lmc_proto_close(lmc_softc_t *sc);
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb);
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb);
+int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused);
+
+#endif
\ No newline at end of file
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto_raw.h linux/drivers/net/wan/lmc/lmc_proto_raw.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto_raw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_proto_raw.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,4 @@
+#ifndef _LMC_PROTO_RAW_H_
+#define _LMC_PROTO_RAW_H_
+
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_var.h linux/drivers/net/wan/lmc/lmc_var.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_var.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_var.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,590 @@
+#ifndef _LMC_VAR_H_
+#define _LMC_VAR_H_
+
+/* $Id: lmc_var.h,v 1.17 2000/04/06 12:16:47 asj Exp $ */
+
+ /*
+  * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+  * All rights reserved.  www.lanmedia.com
+  *
+  * This code is written by:
+  * Andrew Stanley-Jones (asj@cban.com)
+  * Rob Braun (bbraun@vix.com),
+  * Michael Graff (explorer@vix.com) and
+  * Matt Thomas (matt@3am-software.com).
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU Public License version 2, incorporated herein by reference.
+  */
+
+#include <linux/timer.h>
+
+#ifndef __KERNEL__
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 32 
+
+#endif
+
+/*
+ * basic definitions used in lmc include files
+ */
+
+typedef struct lmc___softc lmc_softc_t;
+typedef struct lmc___media lmc_media_t;
+typedef struct lmc___ctl lmc_ctl_t;
+
+#define lmc_csrptr_t    unsigned long
+#define u_int16_t	u16
+#define u_int8_t	u8
+#define tulip_uint32_t	u32
+#if LINUX_VERSION_CODE < 0x20155
+#define u_int32_t	u32
+#endif
+
+#define LMC_REG_RANGE 0x80
+
+#define LMC_PRINTF_FMT  "%s"
+#define LMC_PRINTF_ARGS	(sc->lmc_device->name)
+
+#define TX_TIMEOUT (2*HZ)
+
+#define LMC_TXDESCS            32
+#define LMC_RXDESCS            32
+
+#define LMC_LINK_UP            1
+#define LMC_LINK_DOWN          0
+
+/* These macros for generic read and write to and from the dec chip */
+#define LMC_CSR_READ(sc, csr) \
+	inl((sc)->lmc_csrs.csr)
+#define LMC_CSR_WRITE(sc, reg, val) \
+	outl((val), (sc)->lmc_csrs.reg)
+
+//#ifdef _LINUX_DELAY_H
+//	#define SLOW_DOWN_IO udelay(2);
+//	#undef __SLOW_DOWN_IO
+//	#define __SLOW_DOWN_IO udelay(2);
+//#endif
+
+#define DELAY(n) SLOW_DOWN_IO
+
+#define lmc_delay() inl(sc->lmc_csrs.csr_9)
+
+/* This macro sync's up with the mii so that reads and writes can take place */
+#define LMC_MII_SYNC(sc) do {int n=32; while( n >= 0 ) { \
+                LMC_CSR_WRITE((sc), csr_9, 0x20000); \
+		lmc_delay(); \
+		LMC_CSR_WRITE((sc), csr_9, 0x30000); \
+                lmc_delay(); \
+		n--; }} while(0);
+
+struct lmc_regfile_t {
+    lmc_csrptr_t csr_busmode;                  /* CSR0 */
+    lmc_csrptr_t csr_txpoll;                   /* CSR1 */
+    lmc_csrptr_t csr_rxpoll;                   /* CSR2 */
+    lmc_csrptr_t csr_rxlist;                   /* CSR3 */
+    lmc_csrptr_t csr_txlist;                   /* CSR4 */
+    lmc_csrptr_t csr_status;                   /* CSR5 */
+    lmc_csrptr_t csr_command;                  /* CSR6 */
+    lmc_csrptr_t csr_intr;                     /* CSR7 */
+    lmc_csrptr_t csr_missed_frames;            /* CSR8 */
+    lmc_csrptr_t csr_9;                        /* CSR9 */
+    lmc_csrptr_t csr_10;                       /* CSR10 */
+    lmc_csrptr_t csr_11;                       /* CSR11 */
+    lmc_csrptr_t csr_12;                       /* CSR12 */
+    lmc_csrptr_t csr_13;                       /* CSR13 */
+    lmc_csrptr_t csr_14;                       /* CSR14 */
+    lmc_csrptr_t csr_15;                       /* CSR15 */
+};
+
+#define csr_enetrom             csr_9   /* 21040 */
+#define csr_reserved            csr_10  /* 21040 */
+#define csr_full_duplex         csr_11  /* 21040 */
+#define csr_bootrom             csr_10  /* 21041/21140A/?? */
+#define csr_gp                  csr_12  /* 21140* */
+#define csr_watchdog            csr_15  /* 21140* */
+#define csr_gp_timer            csr_11  /* 21041/21140* */
+#define csr_srom_mii            csr_9   /* 21041/21140* */
+#define csr_sia_status          csr_12  /* 2104x */
+#define csr_sia_connectivity    csr_13  /* 2104x */
+#define csr_sia_tx_rx           csr_14  /* 2104x */
+#define csr_sia_general         csr_15  /* 2104x */
+
+/* tulip length/control transmit descriptor definitions
+ *  used to define bits in the second tulip_desc_t field (length)
+ *  for the transmit descriptor -baz */
+
+#define LMC_TDES_FIRST_BUFFER_SIZE       ((u_int32_t)(0x000007FF))
+#define LMC_TDES_SECOND_BUFFER_SIZE      ((u_int32_t)(0x003FF800))
+#define LMC_TDES_HASH_FILTERING          ((u_int32_t)(0x00400000))
+#define LMC_TDES_DISABLE_PADDING         ((u_int32_t)(0x00800000))
+#define LMC_TDES_SECOND_ADDR_CHAINED     ((u_int32_t)(0x01000000))
+#define LMC_TDES_END_OF_RING             ((u_int32_t)(0x02000000))
+#define LMC_TDES_ADD_CRC_DISABLE         ((u_int32_t)(0x04000000))
+#define LMC_TDES_SETUP_PACKET            ((u_int32_t)(0x08000000))
+#define LMC_TDES_INVERSE_FILTERING       ((u_int32_t)(0x10000000))
+#define LMC_TDES_FIRST_SEGMENT           ((u_int32_t)(0x20000000))
+#define LMC_TDES_LAST_SEGMENT            ((u_int32_t)(0x40000000))
+#define LMC_TDES_INTERRUPT_ON_COMPLETION ((u_int32_t)(0x80000000))
+
+#define TDES_SECOND_BUFFER_SIZE_BIT_NUMBER  11
+#define TDES_COLLISION_COUNT_BIT_NUMBER     3
+
+/* Constants for the RCV descriptor RDES */
+
+#define LMC_RDES_OVERFLOW             ((u_int32_t)(0x00000001))
+#define LMC_RDES_CRC_ERROR            ((u_int32_t)(0x00000002))
+#define LMC_RDES_DRIBBLING_BIT            ((u_int32_t)(0x00000004))
+#define LMC_RDES_REPORT_ON_MII_ERR    ((u_int32_t)(0x00000008))
+#define LMC_RDES_RCV_WATCHDOG_TIMEOUT ((u_int32_t)(0x00000010))
+#define LMC_RDES_FRAME_TYPE           ((u_int32_t)(0x00000020))
+#define LMC_RDES_COLLISION_SEEN       ((u_int32_t)(0x00000040))
+#define LMC_RDES_FRAME_TOO_LONG       ((u_int32_t)(0x00000080))
+#define LMC_RDES_LAST_DESCRIPTOR      ((u_int32_t)(0x00000100))
+#define LMC_RDES_FIRST_DESCRIPTOR     ((u_int32_t)(0x00000200))
+#define LMC_RDES_MULTICAST_FRAME      ((u_int32_t)(0x00000400))
+#define LMC_RDES_RUNT_FRAME           ((u_int32_t)(0x00000800))
+#define LMC_RDES_DATA_TYPE            ((u_int32_t)(0x00003000))
+#define LMC_RDES_LENGTH_ERROR         ((u_int32_t)(0x00004000))
+#define LMC_RDES_ERROR_SUMMARY        ((u_int32_t)(0x00008000))
+#define LMC_RDES_FRAME_LENGTH         ((u_int32_t)(0x3FFF0000))
+#define LMC_RDES_OWN_BIT              ((u_int32_t)(0x80000000))
+
+#define RDES_FRAME_LENGTH_BIT_NUMBER       16
+
+#define LMC_RDES_ERROR_MASK ( (u_int32_t)( \
+	  LMC_RDES_OVERFLOW \
+	| LMC_RDES_DRIBBLING_BIT \
+	| LMC_RDES_REPORT_ON_MII_ERR \
+        | LMC_RDES_COLLISION_SEEN ) )
+
+
+/*
+ * Ioctl info
+ */
+
+typedef struct {
+	u_int32_t	n;
+	u_int32_t	m;
+	u_int32_t	v;
+	u_int32_t	x;
+	u_int32_t	r;
+	u_int32_t	f;
+	u_int32_t	exact;
+} lmc_av9110_t;
+
+/*
+ * Common structure passed to the ioctl code.
+ */
+struct lmc___ctl {
+	u_int32_t	cardtype;
+	u_int32_t	clock_source;		/* HSSI, T1 */
+	u_int32_t	clock_rate;		/* T1 */
+	u_int32_t	crc_length;
+	u_int32_t	cable_length;		/* DS3 */
+	u_int32_t	scrambler_onoff;	/* DS3 */
+	u_int32_t	cable_type;		/* T1 */
+	u_int32_t	keepalive_onoff;	/* protocol */
+	u_int32_t	ticks;			/* ticks/sec */
+	union {
+		lmc_av9110_t	ssi;
+	} cardspec;
+	u_int32_t       circuit_type;   /* T1 or E1 */
+};
+
+
+/*
+ * Carefull, look at the data sheet, there's more to this
+ * structure than meets the eye.  It should probably be:
+ *
+ * struct tulip_desc_t {
+ *         u8  own:1;
+ *         u32 status:31;
+ *         u32 control:10;
+ *         u32 buffer1;
+ *         u32 buffer2;
+ * };
+ * You could also expand status control to provide more bit information
+ */
+
+struct tulip_desc_t {
+	s32 status;
+	s32 length;
+	u32 buffer1;
+	u32 buffer2;
+};
+
+/*
+ * media independent methods to check on media status, link, light LEDs,
+ * etc.
+ */
+struct lmc___media {
+	void	(* init)(lmc_softc_t * const);
+	void	(* defaults)(lmc_softc_t * const);
+	void	(* set_status)(lmc_softc_t * const, lmc_ctl_t *);
+	void	(* set_clock_source)(lmc_softc_t * const, int);
+	void	(* set_speed)(lmc_softc_t * const, lmc_ctl_t *);
+	void	(* set_cable_length)(lmc_softc_t * const, int);
+	void	(* set_scrambler)(lmc_softc_t * const, int);
+	int	(* get_link_status)(lmc_softc_t * const);
+	void	(* set_link_status)(lmc_softc_t * const, int);
+	void	(* set_crc_length)(lmc_softc_t * const, int);
+        void    (* set_circuit_type)(lmc_softc_t * const, int);
+        void	(* watchdog)(lmc_softc_t * const);
+};
+
+
+#define STATCHECK     0xBEEFCAFE
+
+/*  Included in this structure are first
+ *   - standard enet_statistics
+ *   - some other counters used for debug and driver performance
+ *  evaluation -baz
+ */
+struct lmc_statistics
+{
+        unsigned long     rx_packets;             /* total packets received       */
+        unsigned long     tx_packets;             /* total packets transmitted    */
+	unsigned long     rx_bytes;
+        unsigned long     tx_bytes;
+        
+        unsigned long     rx_errors;              /* bad packets received         */
+        unsigned long     tx_errors;              /* packet transmit problems     */
+        unsigned long     rx_dropped;             /* no space in linux buffers    */
+        unsigned long     tx_dropped;             /* no space available in linux  */
+        unsigned long     multicast;              /* multicast packets received   */
+        unsigned long     collisions;
+
+        /* detailed rx_errors: */
+        unsigned long     rx_length_errors;
+        unsigned long     rx_over_errors;         /* receiver ring buff overflow  */
+        unsigned long     rx_crc_errors;          /* recved pkt with crc error    */
+        unsigned long     rx_frame_errors;        /* recv'd frame alignment error */
+        unsigned long     rx_fifo_errors;         /* recv'r fifo overrun          */
+        unsigned long     rx_missed_errors;       /* receiver missed packet       */
+
+        /* detailed tx_errors */
+        unsigned long     tx_aborted_errors;
+        unsigned long     tx_carrier_errors;
+        unsigned long     tx_fifo_errors;
+        unsigned long     tx_heartbeat_errors;
+        unsigned long     tx_window_errors;
+
+        /* for cslip etc */
+        unsigned long rx_compressed;
+        unsigned long tx_compressed;
+
+        /* -------------------------------------
+         * Custom stats & counters follow -baz */
+        u_int32_t       version_size;
+        u_int32_t       lmc_cardtype;
+
+        u_int32_t       tx_ProcTimeout;
+        u_int32_t       tx_IntTimeout;
+        u_int32_t       tx_NoCompleteCnt;
+        u_int32_t       tx_MaxXmtsB4Int;
+        u_int32_t       tx_TimeoutCnt;
+        u_int32_t       tx_OutOfSyncPtr;
+        u_int32_t       tx_tbusy0;
+        u_int32_t       tx_tbusy1;
+        u_int32_t       tx_tbusy_calls;
+        u_int32_t       resetCount;
+        u_int32_t       lmc_txfull;
+        u_int32_t       tbusy;
+        u_int32_t       dirtyTx;
+        u_int32_t       lmc_next_tx;
+        u_int32_t       otherTypeCnt;
+        u_int32_t       lastType;
+        u_int32_t       lastTypeOK;
+        u_int32_t       txLoopCnt;
+        u_int32_t       usedXmtDescripCnt;
+        u_int32_t       txIndexCnt;
+        u_int32_t       rxIntLoopCnt;
+
+        u_int32_t       rx_SmallPktCnt;
+        u_int32_t       rx_BadPktSurgeCnt;
+        u_int32_t       rx_BuffAllocErr;
+        u_int32_t       tx_lossOfClockCnt;
+
+        /* T1 error counters */
+        u_int32_t       framingBitErrorCount;
+        u_int32_t       lineCodeViolationCount;
+
+        u_int32_t       lossOfFrameCount;
+        u_int32_t       changeOfFrameAlignmentCount;
+        u_int32_t       severelyErroredFrameCount;
+
+        u_int32_t       check;
+};
+
+
+typedef struct lmc_xinfo {
+        u_int32_t       Magic0;                         /* BEEFCAFE */
+
+        u_int32_t       PciCardType;
+        u_int32_t       PciSlotNumber;          /* PCI slot number       */
+
+        u_int16_t       DriverMajorVersion;
+        u_int16_t       DriverMinorVersion;
+        u_int16_t       DriverSubVersion;
+
+        u_int16_t       XilinxRevisionNumber;
+        u_int16_t       MaxFrameSize;
+
+        u_int16_t       t1_alarm1_status;
+        u_int16_t       t1_alarm2_status;
+
+        int                     link_status;
+        u_int32_t       mii_reg16;
+
+        u_int32_t       Magic1;                         /* DEADBEEF */
+} LMC_XINFO;
+
+
+/*
+ * forward decl
+ */
+struct lmc___softc {
+        void *if_ptr;   /* General purpose pointer (used by SPPP) */
+	char                   *name;
+	u8			board_idx;
+	struct lmc_statistics   stats;
+	struct net_device          *lmc_device;
+
+	int                     hang, rxdesc, bad_packet, some_counter;
+	u_int32_t               txgo;
+	struct lmc_regfile_t	lmc_csrs;
+	volatile u_int32_t	lmc_txtick;
+	volatile u_int32_t	lmc_rxtick;
+	u_int32_t		lmc_flags;
+	u_int32_t		lmc_intrmask;	/* our copy of csr_intr */
+	u_int32_t		lmc_cmdmode;	/* our copy of csr_cmdmode */
+	u_int32_t		lmc_busmode;	/* our copy of csr_busmode */
+	u_int32_t		lmc_gpio_io;	/* state of in/out settings */
+	u_int32_t		lmc_gpio;	/* state of outputs */
+	struct sk_buff*		lmc_txq[LMC_TXDESCS];
+	struct sk_buff*		lmc_rxq[LMC_RXDESCS];
+	volatile
+	struct tulip_desc_t	lmc_rxring[LMC_RXDESCS];
+	volatile
+	struct tulip_desc_t	lmc_txring[LMC_TXDESCS];
+	unsigned int		lmc_next_rx, lmc_next_tx;
+	volatile
+	unsigned int		lmc_taint_tx, lmc_taint_rx;
+	int			lmc_tx_start, lmc_txfull;
+	int			lmc_txbusy;
+	u_int16_t		lmc_miireg16;
+	int			lmc_ok;
+	int			last_link_status;
+	int			lmc_cardtype;
+	u_int32_t               last_frameerr;
+	lmc_media_t	       *lmc_media;
+	struct timer_list	timer;
+	lmc_ctl_t		ictl;
+	u_int32_t		TxDescriptControlInit;  
+	struct net_device		*next_module;   /* Link to the next module  */
+	int                     tx_TimeoutInd; /* additional driver state */
+	int                     tx_TimeoutDisplay;
+	unsigned int		lastlmc_taint_tx;
+	int                     lasttx_packets;
+	u_int32_t		tx_clockState;
+	u_int32_t		lmc_crcSize;
+	LMC_XINFO		lmc_xinfo; 
+	char                    lmc_yel, lmc_blue, lmc_red; /* for T1 and DS3 */
+        char                    lmc_timing; /* for HSSI and SSI */
+        int                     got_irq;
+
+        char                    last_led_err[4];
+
+        u32                     last_int;
+        u32                     num_int;
+
+#if LINUX_VERSION_CODE >= 0x20200
+	spinlock_t              lmc_lock;
+#endif
+        u_int16_t               if_type;       /* PPP or NET */
+        struct ppp_device       *pd;
+
+        /* Failure cases */
+        u8                       failed_ring;
+        u8                       failed_recv_alloc;
+
+        /* Structure check */
+        u32                     check;
+};
+
+#define LMC_PCI_TIME 1
+#define LMC_EXT_TIME 0
+
+#define PKT_BUF_SZ              1542  /* was 1536 */
+
+/* CSR5 settings */
+#define TIMER_INT     0x00000800
+#define TP_LINK_FAIL  0x00001000
+#define TP_LINK_PASS  0x00000010
+#define NORMAL_INT    0x00010000
+#define ABNORMAL_INT  0x00008000
+#define RX_JABBER_INT 0x00000200
+#define RX_DIED       0x00000100
+#define RX_NOBUFF     0x00000080
+#define RX_INT        0x00000040
+#define TX_FIFO_UNDER 0x00000020
+#define TX_JABBER     0x00000008
+#define TX_NOBUFF     0x00000004
+#define TX_DIED       0x00000002
+#define TX_INT        0x00000001
+
+/* CSR6 settings */
+#define OPERATION_MODE  0x00000200 /* Full Duplex      */
+#define PROMISC_MODE    0x00000040 /* Promiscuous Mode */
+#define RECIEVE_ALL     0x40000000 /* Recieve All      */
+#define PASS_BAD_FRAMES 0x00000008 /* Pass Bad Frames  */
+
+/* Dec control registers  CSR6 as well */
+#define LMC_DEC_ST 0x00002000
+#define LMC_DEC_SR 0x00000002
+
+/* CSR15 settings */
+#define RECV_WATCHDOG_DISABLE 0x00000010
+#define JABBER_DISABLE        0x00000001
+
+/* More settings */
+/*
+ * aSR6 -- Command (Operation Mode) Register
+ */
+#define TULIP_CMD_RECEIVEALL    0x40000000L /* (RW)  Receivel all frames? */
+#define TULIP_CMD_MUSTBEONE     0x02000000L /* (RW)  Must Be One (21140) */
+#define TULIP_CMD_TXTHRSHLDCTL  0x00400000L /* (RW)  Transmit Threshold Mode (21140) */
+#define TULIP_CMD_STOREFWD      0x00200000L /* (RW)  Store and Foward (21140) */
+#define TULIP_CMD_NOHEARTBEAT   0x00080000L /* (RW)  No Heartbeat (21140) */
+#define TULIP_CMD_PORTSELECT    0x00040000L /* (RW)  Post Select (100Mb) (21140) */
+#define TULIP_CMD_FULLDUPLEX    0x00000200L /* (RW)  Full Duplex Mode */
+#define TULIP_CMD_OPERMODE      0x00000C00L /* (RW)  Operating Mode */
+#define TULIP_CMD_PROMISCUOUS   0x00000041L /* (RW)  Promiscuous Mode */
+#define TULIP_CMD_PASSBADPKT    0x00000008L /* (RW)  Pass Bad Frames */
+#define TULIP_CMD_THRESHOLDCTL  0x0000C000L /* (RW)  Threshold Control */
+
+#define TULIP_GP_PINSET         0x00000100L
+#define TULIP_BUSMODE_SWRESET   0x00000001L
+#define TULIP_WATCHDOG_TXDISABLE 0x00000001L
+#define TULIP_WATCHDOG_RXDISABLE 0x00000010L
+
+#define TULIP_STS_NORMALINTR    0x00010000L /* (RW)  Normal Interrupt */
+#define TULIP_STS_ABNRMLINTR    0x00008000L /* (RW)  Abnormal Interrupt */
+#define TULIP_STS_ERI           0x00004000L /* (RW)  Early Receive Interupt */
+#define TULIP_STS_SYSERROR      0x00002000L /* (RW)  System Error */
+#define TULIP_STS_GTE           0x00000800L /* (RW)  General Pupose Timer Exp */
+#define TULIP_STS_ETI           0x00000400L /* (RW)  Early Transmit Interupt */
+#define TULIP_STS_RXWT          0x00000200L /* (RW)  Receiver Watchdog Timeout */
+#define TULIP_STS_RXSTOPPED     0x00000100L /* (RW)  Receiver Process Stopped */
+#define TULIP_STS_RXNOBUF       0x00000080L /* (RW)  Receive Buf Unavail */
+#define TULIP_STS_RXINTR        0x00000040L /* (RW)  Receive Interrupt */
+#define TULIP_STS_TXUNDERFLOW   0x00000020L /* (RW)  Transmit Underflow */
+#define TULIP_STS_TXJABER       0x00000008L /* (RW)  Jabber timeout */
+#define TULIP_STS_TXNOBUF       0x00000004L
+#define TULIP_STS_TXSTOPPED     0x00000002L /* (RW)  Transmit Process Stopped */
+#define TULIP_STS_TXINTR        0x00000001L /* (RW)  Transmit Interrupt */
+
+#define TULIP_STS_RXS_STOPPED   0x00000000L /*        000 - Stopped */
+
+#define TULIP_STS_RXSTOPPED     0x00000100L             /* (RW)  Receive Process Stopped */
+#define TULIP_STS_RXNOBUF       0x00000080L
+
+#define TULIP_CMD_TXRUN         0x00002000L /* (RW)  Start/Stop Transmitter */
+#define TULIP_CMD_RXRUN         0x00000002L /* (RW)  Start/Stop Receive Filtering */
+#define TULIP_DSTS_TxDEFERRED   0x00000001      /* Initially Deferred */
+#define TULIP_DSTS_OWNER        0x80000000      /* Owner (1 = 21040) */
+#define TULIP_DSTS_RxMIIERR     0x00000008
+#define LMC_DSTS_ERRSUM         (TULIP_DSTS_RxMIIERR)
+
+#define TULIP_DEFAULT_INTR_MASK  (TULIP_STS_NORMALINTR \
+  | TULIP_STS_RXINTR       \
+  | TULIP_STS_TXINTR     \
+  | TULIP_STS_ABNRMLINTR \
+  | TULIP_STS_SYSERROR   \
+  | TULIP_STS_TXSTOPPED  \
+  | TULIP_STS_TXUNDERFLOW\
+  | TULIP_STS_RXSTOPPED )
+
+#define DESC_OWNED_BY_SYSTEM   ((u_int32_t)(0x00000000))
+#define DESC_OWNED_BY_DC21X4   ((u_int32_t)(0x80000000))
+
+#ifndef TULIP_CMD_RECEIVEALL
+#define TULIP_CMD_RECEIVEALL 0x40000000L
+#endif
+
+
+/* PCI register values */
+#define CORRECT_VENDOR_ID    0x1011
+#define CORRECT_DEV_ID       9
+
+#define PCI_VENDOR_LMC		0x1376
+#define PCI_PRODUCT_LMC_HSSI	0x0003
+#define PCI_PRODUCT_LMC_DS3	0x0004
+#define PCI_PRODUCT_LMC_SSI	0x0005
+#define PCI_PRODUCT_LMC_T1      0x0006
+
+/* Adapcter module number */
+#define LMC_ADAP_HSSI           2
+#define LMC_ADAP_DS3            3
+#define LMC_ADAP_SSI            4
+#define LMC_ADAP_T1             5
+
+#define HDLC_HDR_LEN  4
+#define HDLC_ADDR_LEN 1
+#define HDLC_SLARP    0x8035
+#define LMC_MTU 1500
+#define SLARP_LINECHECK 2
+
+#define LMC_CRC_LEN_16 2  /* 16-bit CRC */
+#define LMC_CRC_LEN_32 4
+
+#if LINUX_VERSION_CODE < 0x20100
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
+#ifdef LMC_HDLC
+/* definition of an hdlc header. */
+struct hdlc_hdr
+{
+	u8  address;
+	u8  control;
+	u16 type;
+};
+
+/* definition of a slarp header. */
+struct slarp
+{
+	long code;
+	union sl
+	{
+		struct
+		{
+			ulong address;
+			ulong mask;
+			ushort unused;
+		} add;
+		struct
+		{
+			ulong mysequence;
+			ulong yoursequence;
+			ushort reliability;
+			ulong time;
+		} chk;
+	} t;
+};
+#endif /* LMC_HDLC */
+
+
+#endif /* _LMC_VAR_H_ */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ver.h linux/drivers/net/wan/lmc/lmc_ver.h
--- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ver.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/lmc/lmc_ver.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,123 @@
+#ifndef _IF_LMC_LINUXVER_
+#define _IF_LMC_LINUXVER_
+
+ /*
+  * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+  * All rights reserved.  www.lanmedia.com
+  *
+  * This code is written by:
+  * Andrew Stanley-Jones (asj@cban.com)
+  * Rob Braun (bbraun@vix.com),
+  * Michael Graff (explorer@vix.com) and
+  * Matt Thomas (matt@3am-software.com).
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU Public License version 2, incorporated herein by reference.
+  */
+
+ /*
+  * This file defines and controls all linux version
+  * differences.
+  *
+  * This is being done to keep 1 central location where all linux
+  * version differences can be kept and maintained.  as this code was
+  * found version issues where pepered throughout the source code and
+  * made the souce code not only hard to read but version problems hard
+  * to track down.  If I'm overiding a function/etc with something in
+  * this file it will be prefixed by "LMC_" which will mean look
+  * here for the the version dependant change that's been done.
+  *
+  */
+
+#if LINUX_VERSION_CODE < 0x20363
+#define net_device device
+#endif
+
+#if LINUX_VERSION_CODE < 0x20363
+#define LMC_XMITTER_BUSY(x) (x)->tbusy = 1
+#define LMC_XMITTER_FREE(x) (x)->tbusy = 0
+#define LMC_XMITTER_INIT(x) (x)->tbusy = 0
+#else
+#define LMC_XMITTER_BUSY(x) netif_stop_queue(x)
+#define LMC_XMITTER_FREE(x) netif_wake_queue(x)
+#define LMC_XMITTER_INIT(x) netif_start_queue(x)
+
+#endif
+
+
+#if LINUX_VERSION_CODE < 0x20100
+//typedef unsigned int u_int32_t;
+
+#define  LMC_SETUP_20_DEV {\
+                             int indx; \
+                             for (indx = 0; indx < DEV_NUMBUFFS; indx++) \
+                                skb_queue_head_init (&dev->buffs[indx]); \
+                          } \
+                          dev->family = AF_INET; \
+                          dev->pa_addr = 0; \
+                          dev->pa_brdaddr = 0; \
+                          dev->pa_mask = 0xFCFFFFFF; \
+                          dev->pa_alen = 4;		/* IP addr.  sizeof(u32) */
+
+#else
+
+#define LMC_SETUP_20_DEV
+
+#endif
+
+
+#if LINUX_VERSION_CODE < 0x20155 /* basically 2.2 plus */
+
+#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb((skb), FREE_WRITE)
+#define LMC_PCI_PRESENT() pcibios_present()
+
+#else /* Mostly 2.0 kernels */
+
+#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define LMC_PCI_PRESENT() pci_present()
+
+#endif
+
+#if LINUX_VERSION_CODE < 0x20200
+#else
+
+#endif
+
+#if LINUX_VERSION_CODE < 0x20100
+#define LMC_SKB_FREE(skb, val) (skb->free = val)
+#else
+#define LMC_SKB_FREE(skb, val)
+#endif
+
+
+#if (LINUX_VERSION_CODE >= 0x20200)
+
+#define LMC_SPIN_FLAGS                unsigned long flags;
+#define LMC_SPIN_LOCK_INIT(x)         spin_lock_init(&(x)->lmc_lock);
+#define LMC_SPIN_UNLOCK(x)            ((x)->lmc_lock = SPIN_LOCK_UNLOCKED)
+#define LMC_SPIN_LOCK_IRQSAVE(x)      spin_lock_irqsave (&(x)->lmc_lock, flags);
+#define LMC_SPIN_UNLOCK_IRQRESTORE(x) spin_unlock_irqrestore (&(x)->lmc_lock, flags);
+#else
+#define LMC_SPIN_FLAGS
+#define LMC_SPIN_LOCK_INIT(x)
+#define LMC_SPIN_UNLOCK(x)
+#define LMC_SPIN_LOCK_IRQSAVE(x)
+#define LMC_SPIN_UNLOCK_IRQRESTORE(x)
+#endif
+
+
+#if LINUX_VERSION_CODE >= 0x20100
+#define LMC_COPY_FROM_USER(x, y, z) if(copy_from_user ((x), (y), (z))) return -EFAULT
+#define LMC_COPY_TO_USER(x, y, z) if(copy_to_user ((x), (y), (z))) return -EFAULT
+#else
+#define LMC_COPY_FROM_USER(x, y, z) if(verify_area(VERIFY_READ, (y), (z))) \
+			               return -EFAULT; \
+                                    memcpy_fromfs ((x), (y), (z))
+
+#define LMC_COPY_TO_USER(x, y, z)   if(verify_area(VERIFY_WRITE, (x), (z))) \
+	                               return -EFAULT; \
+                                    memcpy_tofs ((x), (y), (z))
+#endif
+
+
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- v2.3.99-pre5/linux/drivers/net/wan/sdla_chdlc.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/wan/sdla_chdlc.c	Fri Apr 21 16:08:45 2000
@@ -22,6 +22,7 @@
 * Aug 07, 1998	David Fong	Initial version.
 *****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
@@ -2762,7 +2763,7 @@
 
 void s508_lock (sdla_t *card, unsigned long *smp_flags)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
                 spin_lock_irqsave(&card->lock, *smp_flags);
                 if (card->next){
                         spin_lock(&card->next->lock);
@@ -2774,7 +2775,7 @@
 
 void s508_unlock (sdla_t *card, unsigned long *smp_flags)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
                         if (card->next){
                                 spin_unlock(&card->next->lock);
                         }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- v2.3.99-pre5/linux/drivers/net/wan/sdla_fr.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/wan/sdla_fr.c	Fri Apr 21 16:08:45 2000
@@ -109,6 +109,7 @@
 * Jan 02, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -3677,13 +3678,13 @@
 {
 
 	if (card->hw.type != SDLA_S514){
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		spin_lock_irqsave(&card->lock, *smp_flags);
 #else
     		disable_irq(card->hw.irq);
 #endif
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	else{
 		spin_lock(&card->lock);
 	}	
@@ -3693,13 +3694,13 @@
 void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags)
 {
 	if (card->hw.type != SDLA_S514){
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		spin_unlock_irqrestore(&card->lock, *smp_flags);
 #else
     		enable_irq(card->hw.irq);
 #endif
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	else{
 		spin_unlock(&card->lock);
 	}	
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c
--- v2.3.99-pre5/linux/drivers/net/wan/sdla_ppp.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/wan/sdla_ppp.c	Fri Apr 21 16:08:45 2000
@@ -74,6 +74,7 @@
 * Jan 06, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
@@ -2896,7 +2897,7 @@
 
 void s508_lock (sdla_t *card, unsigned long *smp_flags)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	spin_lock_irqsave(&card->lock, *smp_flags);
 #else
 	disable_irq(card->hw.irq);
@@ -2905,7 +2906,7 @@
 
 void s508_unlock (sdla_t *card, unsigned long *smp_flags)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
         spin_unlock_irqrestore(&card->lock, *smp_flags);
 #else
 	enable_irq(card->hw.irq);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c
--- v2.3.99-pre5/linux/drivers/net/wan/sdladrv.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/wan/sdladrv.c	Wed Apr 12 09:38:57 2000
@@ -308,7 +308,7 @@
 #ifdef MODULE
 int init_module (void)
 #else
-__initfunc(int wanpipe_init(void))
+int __init wanpipe_init(void)
 #endif
 {
 	printk(KERN_INFO "%s v%u.%u %s\n",
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c
--- v2.3.99-pre5/linux/drivers/net/wan/sdlamain.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/wan/sdlamain.c	Fri Apr 21 16:08:45 2000
@@ -391,7 +391,7 @@
 
 	if (!card->configured){
 
-	#ifdef __SMP__
+	#ifdef CONFIG_SMP
 		/* Initialize the Spin lock */
 		printk(KERN_INFO "%s: Initializing SMP\n",wandev->name);
 		spin_lock_init(&card->lock);
@@ -825,13 +825,13 @@
 
 		/* Use spin lock only for S508 */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		spin_lock(&card->lock);
 #endif
 		sdla_intack(&card->hw);
 		if (card->isr)
 			card->isr(card);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		spin_unlock(&card->lock);
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c
--- v2.3.99-pre5/linux/drivers/net/wan/syncppp.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/net/wan/syncppp.c	Fri Apr 21 16:08:45 2000
@@ -33,7 +33,7 @@
  *
  * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
  *
- * $Id: if_spppsubr.c,v 1.12 1996/06/10 23:17:45 gpalmer Exp $
+ * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $
  */
 #undef DEBUG
 
@@ -193,7 +193,7 @@
  *
  *	This can be called directly by cards that do not have
  *	timing constraints but is normally called from the network layer
- *	after interrupt servicing to process frames queued via netif_rx.
+ *	after interrupt servicing to process frames queued via netif_rx().
  *
  *	We process the options in the card. If the frame is destined for
  *	the protocol stacks then it requeues the frame for the upper level
@@ -395,7 +395,7 @@
 
 		if (sp->pp_alivecnt == MAXALIVECNT) {
 			/* No keepalive packets got.  Stop the interface. */
-			printk (KERN_WARNING "%s: down\n", dev->name);
+			printk (KERN_WARNING "%s: protocol down\n", dev->name);
 			if_down (dev);
 			if (! (sp->pp_flags & PP_CISCO)) {
 				/* Shut down the PPP link. */
@@ -529,7 +529,6 @@
 			sppp_ipcp_open (sp);
 			break;
 		case LCP_STATE_OPENED:
-#if 0		
 			/* Remote magic changed -- close session. */
 			sp->lcp.state = LCP_STATE_CLOSED;
 			sp->ipcp.state = IPCP_STATE_CLOSED;
@@ -537,7 +536,6 @@
 			sppp_lcp_open (sp);
 			/* An ACK has already been sent. */
 			sp->lcp.state = LCP_STATE_ACK_SENT;
-#endif			
 			break;
 		}
 		break;
@@ -549,7 +547,7 @@
 		    (dev->flags & IFF_UP)) {
 			/* Coming out of loopback mode. */
 			sp->pp_link_state=SPPP_LINK_UP;
-			printk (KERN_INFO "%s: up\n", dev->name);
+			printk (KERN_INFO "%s: protocol up\n", dev->name);
 		}
 		switch (sp->lcp.state) {
 		case LCP_STATE_CLOSED:
@@ -716,7 +714,7 @@
 		if (sp->pp_link_state==SPPP_LINK_DOWN &&
 		    (dev->flags & IFF_UP)) {
 			sp->pp_link_state=SPPP_LINK_UP;
-			printk (KERN_INFO "%s: up\n", dev->name);
+			printk (KERN_INFO "%s: protocol up\n", dev->name);
 		}
 		break;
 	case CISCO_ADDR_REQ:
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c
--- v2.3.99-pre5/linux/drivers/net/wan/z85230.c	Tue Apr 11 15:09:18 2000
+++ linux/drivers/net/wan/z85230.c	Wed Apr 12 09:47:26 2000
@@ -1313,12 +1313,12 @@
 /**
  *	z8530_channel_load - Load channel data
  *	@c: Z8530 channel to configure
- *	@rtable: Table of register, value pairs
+ *	@rtable: table of register, value pairs
  *	FIXME: ioctl to allow user uploaded tables
  *
  *	Load a Z8530 channel up from the system data. We use +16 to 
- *	indicate the 'prime' registers. The value 255 terminates the
- *	table
+ *	indicate the "prime" registers. The value 255 terminates the
+ *	table.
  */
 
 int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.3.99-pre5/linux/drivers/net/yellowfin.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/net/yellowfin.c	Fri Apr 21 16:08:52 2000
@@ -1418,7 +1418,6 @@
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__  -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`  -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- v2.3.99-pre5/linux/drivers/parport/ChangeLog	Tue Apr 11 15:09:18 2000
+++ linux/drivers/parport/ChangeLog	Thu Apr 13 09:25:44 2000
@@ -1,3 +1,20 @@
+2000-04-04  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Add support for another PCI card.
+
+2000-04-04  Tim Waugh  <twaugh@redhat.com>
+
+	* daisy.c: Documentation in kernel-doc format.
+
+	* ieee1284.c: Likewise.
+
+	* share.c: Likewise.
+
+2000-04-01  Tim Waugh  <twaugh@redhat.com>
+
+	* share.c (parport_register_device): Need to hold the module
+	reference counts before sleeping.
+
 2000-03-27  Tim Waugh  <twaugh@redhat.com>
 
 	* parport_pc.c (parport_pc_ecp_read_block_pio): Correct operation
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/daisy.c linux/drivers/parport/daisy.c
--- v2.3.99-pre5/linux/drivers/parport/daisy.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/parport/daisy.c	Wed Apr 12 09:47:26 2000
@@ -174,7 +174,26 @@
 	return;
 }
 
-/* Find a device by canonical device number. */
+/**
+ *	parport_open - find a device by canonical device number
+ *	@devnum: canonical device number
+ *	@name: name to associate with the device
+ *	@pf: preemption callback
+ *	@kf: kick callback
+ *	@irqf: interrupt handler
+ *	@flags: registration flags
+ *	@handle: driver data
+ *
+ *	This function is similar to parport_register_device(), except
+ *	that it locates a device by its number rather than by the port
+ *	it is attached to.  See parport_find_device() and
+ *	parport_find_class().
+ *
+ *	All parameters except for @devnum are the same as for
+ *	parport_register_device().  The return value is the same as
+ *	for parport_register_device().
+ **/
+
 struct pardevice *parport_open (int devnum, const char *name,
 				int (*pf) (void *), void (*kf) (void *),
 				void (*irqf) (int, void *, struct pt_regs *),
@@ -219,13 +238,32 @@
 	return dev;
 }
 
-/* The converse of parport_open. */
+/**
+ *	parport_close - close a device opened with parport_open()
+ *	@dev: device to close
+ *
+ *	This is to parport_open() as parport_unregister_device() is to
+ *	parport_register_device().
+ **/
+
 void parport_close (struct pardevice *dev)
 {
 	parport_unregister_device (dev);
 }
 
-/* Convert device coordinates into a canonical device number. */
+/**
+ *	parport_device_num - convert device coordinates into a
+ *			     canonical device number
+ *	@parport: parallel port number
+ *	@mux: multiplexor port number (-1 for no multiplexor)
+ *	@daisy: daisy chain address (-1 for no daisy chain address)
+ *
+ *	This tries to locate a device on the given parallel port,
+ *	multiplexor port and daisy chain address, and returns its
+ *	device number or -NXIO if no device with those coordinates
+ *	exists.
+ **/
+
 int parport_device_num (int parport, int mux, int daisy)
 {
 	struct daisydev *dev = topology;
@@ -240,7 +278,32 @@
 	return dev->devnum;
 }
 
-/* Convert a canonical device number into device coordinates. */
+/**
+ *	parport_device_coords - convert a canonical device number into
+ *				device coordinates
+ *	@devnum: device number
+ *	@parport: pointer to storage for parallel port number
+ *	@mux: pointer to storage for multiplexor port number
+ *	@daisy: pointer to storage for daisy chain address
+ *
+ *	This function converts a device number into its coordinates in
+ *	terms of which parallel port in the system it is attached to,
+ *	which multiplexor port it is attached to if there is a
+ *	multiplexor on that port, and which daisy chain address it has
+ *	if it is in a daisy chain.
+ *
+ *	The caller must allocate storage for @parport, @mux, and
+ *	@daisy.
+ *
+ *	If there is no device with the specified device number, -ENXIO
+ *	is returned.  Otherwise, the values pointed to by @parport,
+ *	@mux, and @daisy are set to the coordinates of the device,
+ *	with -1 for coordinates with no value.
+ *
+ *	This function is not actually very useful, but this interface
+ *	was suggested by IEEE 1284.3.
+ **/
+
 int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
 {
 	struct daisydev *dev = topology;
@@ -437,6 +500,28 @@
 /* Find a device with a particular manufacturer and model string,
    starting from a given device number.  Like the PCI equivalent,
    'from' itself is skipped. */
+
+/**
+ *	parport_find_device - find a device with a specified
+ *			      manufacturer and model string
+ *	@mfg: required manufacturer string
+ *	@mdl: required model string
+ *	@from: previous device number found in search, or %NULL for
+ *	       new search
+ *
+ *	This walks through the list of parallel port devices looking
+ *	for a device whose 'MFG' string matches @mfg and whose 'MDL'
+ *	string matches @mdl in their IEEE 1284 Device ID.
+ *
+ *	When a device is found matching those requirements, its device
+ *	number is returned; if there is no matching device, a negative
+ *	value is returned.
+ *
+ *	A new search it initiated by passing %NULL as the @from
+ *	argument.  If @from is not %NULL, the search continues from
+ *	that device.
+ **/
+
 int parport_find_device (const char *mfg, const char *mdl, int from)
 {
 	struct daisydev *d = topology; /* sorted by devnum */
@@ -462,8 +547,25 @@
 	return -1;
 }
 
-/* Find a device in a particular class.  Like the PCI equivalent,
-   'from' itself is skipped. */
+/**
+ *	parport_find_class - find a device in a specified class
+ *	@cls: required class
+ *	@from: previous device number found in search, or %NULL for
+ *	       new search
+ *
+ *	This walks through the list of parallel port devices looking
+ *	for a device whose 'CLS' string matches @cls in their IEEE
+ *	1284 Device ID.
+ *
+ *	When a device is found matching those requirements, its device
+ *	number is returned; if there is no matching device, a negative
+ *	value is returned.
+ *
+ *	A new search it initiated by passing %NULL as the @from
+ *	argument.  If @from is not %NULL, the search continues from
+ *	that device.
+ **/
+
 int parport_find_class (parport_device_class cls, int from)
 {
 	struct daisydev *d = topology; /* sorted by devnum */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- v2.3.99-pre5/linux/drivers/parport/ieee1284.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/parport/ieee1284.c	Wed Apr 12 09:47:26 2000
@@ -42,11 +42,22 @@
 	parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
 }
 
-/* Wait for a parport_ieee1284_wakeup.
- * 0:      success
- * <0:     error (exit as soon as possible)
- * >0:     timed out
+/**
+ *	parport_wait_event - wait for an event on a parallel port
+ *	@port: port to wait on
+ *	@timeout: time to wait (in jiffies)
+ *
+ *	This function waits for up to @timeout jiffies for an
+ *	interrupt to occur on a parallel port.  If the port timeout is
+ *	set to zero, it returns immediately.
+ *
+ *	If an interrupt occurs before the timeout period elapses, this
+ *	function returns one immediately.  If it times out, it returns
+ *	a value greater than zero.  An error code less than zero
+ *	indicates an error (most likely a pending signal), and the
+ *	calling code should finish what it's doing as soon as it can.
  */
+
 int parport_wait_event (struct parport *port, signed long timeout)
 {
 	int ret;
@@ -72,13 +83,29 @@
 	return ret;
 }
 
-/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
- * 25 for this. After this time we can create a timeout because the
- * peripheral doesn't conform to IEEE1284.  We want to save CPU time: we are
- * waiting a maximum time of 500 us busy (this is for speed).  If there is
- * not the right answer in this time, we call schedule and other processes
- * are able to eat the time up to 40ms.
- */ 
+/**
+ *	parport_poll_peripheral - poll status lines
+ *	@port: port to watch
+ *	@mask: status lines to watch
+ *	@result: desired values of chosen status lines
+ *	@usec: timeout
+ *
+ *	This function busy-waits until the masked status lines have
+ *	the desired values, or until the timeout period elapses.  The
+ *	@mask and @result parameters are bitmasks, with the bits
+ *	defined by the constants in parport.h: %PARPORT_STATUS_BUSY,
+ *	and so on.
+ *
+ *	This function does not call schedule(); instead it busy-waits
+ *	using udelay().  It currently has a resolution of 5usec.
+ *
+ *	If the status lines take on the desired values before the
+ *	timeout period elapses, parport_poll_peripheral() returns zero
+ *	immediately.  A zero return value greater than zero indicates
+ *	a timeout.  An error code (less than zero) indicates an error,
+ *	most likely a signal that arrived, and the caller should
+ *	finish what it is doing as soon as possible.
+*/
 
 int parport_poll_peripheral(struct parport *port,
 			    unsigned char mask,
@@ -102,6 +129,31 @@
 	return 1;
 }
 
+/**
+ *	parport_wait_peripheral - wait for status lines to change in 35ms
+ *	@port: port to watch
+ *	@mask: status lines to watch
+ *	@result: desired values of chosen status lines
+ *
+ *	This function waits until the masked status lines have the
+ *	desired values, or until 35ms have elapsed (see IEEE 1284-1994
+ *	page 24 to 25 for why this value in particular is hardcoded).
+ *	The @mask and @result parameters are bitmasks, with the bits
+ *	defined by the constants in parport.h: %PARPORT_STATUS_BUSY,
+ *	and so on.
+ *
+ *	The port is polled quickly to start off with, in anticipation
+ *	of a fast response from the peripheral.  This fast polling
+ *	time is configurable (using /proc), and defaults to 500usec.
+ *	If the timeout for this port (see parport_set_timeout()) is
+ *	zero, the fast polling time is 35ms, and this function does
+ *	not call schedule().
+ *
+ *	If the timeout for this port is non-zero, after the fast
+ *	polling fails it uses parport_wait_event() to wait for up to
+ *	10ms, waking up if an interrupt occurs.
+ */
+
 int parport_wait_peripheral(struct parport *port,
 			    unsigned char mask, 
 			    unsigned char result)
@@ -255,12 +307,21 @@
 }		
 #endif /* IEEE1284 support */
 
-/* Negotiate an IEEE 1284 mode.
- * return values are:
- *   0 - handshake OK; IEEE1284 peripheral and mode available
- *  -1 - handshake failed; peripheral is not compliant (or none present)
- *   1 - handshake OK; IEEE1284 peripheral present but mode not available
+/**
+ *	parport_negotiate - negotiate an IEEE 1284 mode
+ *	@port: port to use
+ *	@mode: mode to negotiate to
+ *
+ *	Use this to negotiate to a particular IEEE 1284 transfer mode.
+ *	The @mode parameter should be one of the constants in
+ *	parport.h starting %IEEE1284_MODE_xxx.
+ *
+ *	The return value is 0 if the peripheral has accepted the
+ *	negotiation to the mode specified, -1 if the peripheral is not
+ *	IEEE 1284 compliant (or not present), or 1 if the peripheral
+ *	has rejected the negotiation.
  */
+
 int parport_negotiate (struct parport *port, int mode)
 {
 #ifndef CONFIG_PARPORT_1284
@@ -513,7 +574,24 @@
 #endif /* IEEE1284 support */
 }
 
-/* Write a block of data. */
+/**
+ *	parport_write - write a block of data to a parallel port
+ *	@port: port to write to
+ *	@buffer: data buffer (in kernel space)
+ *	@len: number of bytes of data to transfer
+ *
+ *	This will write up to @len bytes of @buffer to the port
+ *	specified, using the IEEE 1284 transfer mode most recently
+ *	negotiated to (using parport_negotiate()), as long as that
+ *	mode supports forward transfers (host to peripheral).
+ *
+ *	It is the caller's responsibility to ensure that the first
+ *	@len bytes of @buffer are valid.
+ *
+ *	This function returns the number of bytes transferred (if zero
+ *	or positive), or else an error code.
+ */
+
 ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
 {
 #ifndef CONFIG_PARPORT_1284
@@ -578,7 +656,24 @@
 #endif /* IEEE1284 support */
 }
 
-/* Read a block of data. */
+/**
+ *	parport_read - read a block of data from a parallel port
+ *	@port: port to read from
+ *	@buffer: data buffer (in kernel space)
+ *	@len: number of bytes of data to transfer
+ *
+ *	This will read up to @len bytes of @buffer to the port
+ *	specified, using the IEEE 1284 transfer mode most recently
+ *	negotiated to (using parport_negotiate()), as long as that
+ *	mode supports reverse transfers (peripheral to host).
+ *
+ *	It is the caller's responsibility to ensure that the first
+ *	@len bytes of @buffer are available to write to.
+ *
+ *	This function returns the number of bytes transferred (if zero
+ *	or positive), or else an error code.
+ */
+
 ssize_t parport_read (struct parport *port, void *buffer, size_t len)
 {
 #ifndef CONFIG_PARPORT_1284
@@ -637,7 +732,23 @@
 #endif /* IEEE1284 support */
 }
 
-/* Set the amount of time we wait while nothing's happening. */
+/**
+ *	parport_set_timeout - set the inactivity timeout for a device
+ *	                      on a port
+ *	@dev: device on a port
+ *	@inactivity: inactivity timeout (in jiffies)
+ *
+ *	This sets the inactivity timeout for a particular device on a
+ *	port.  This affects functions like parport_wait_peripheral().
+ *	The special value 0 means not to call schedule() while dealing
+ *	with this device.
+ *
+ *	The return value is the previous inactivity timeout.
+ *
+ *	Any callers of parport_wait_event() for this device are woken
+ *	up.
+ */
+
 long parport_set_timeout (struct pardevice *dev, long inactivity)
 {
 	long int old = dev->timeout;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.99-pre5/linux/drivers/parport/parport_pc.c	Tue Apr 11 15:09:18 2000
+++ linux/drivers/parport/parport_pc.c	Fri Apr 21 15:56:02 2000
@@ -427,6 +427,8 @@
 	size_t got;
 
 	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	parport_pc_data_reverse (port);
+	parport_pc_write_control (port, 0x4);
 	got = parport_pc_epp_read_data (port, buf, length, flags);
 	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
 
@@ -440,6 +442,8 @@
 	size_t written;
 
 	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	parport_pc_write_control (port, 0x4);
+	parport_pc_data_forward (port);
 	written = parport_pc_epp_write_data (port, buf, length, flags);
 	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
 
@@ -452,6 +456,8 @@
 	size_t got;
 
 	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	parport_pc_data_reverse (port);
+	parport_pc_write_control (port, 0x4);
 	got = parport_pc_epp_read_addr (port, buf, length, flags);
 	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
 
@@ -465,6 +471,8 @@
 	size_t written;
 
 	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	parport_pc_write_control (port, 0x4);
+	parport_pc_data_forward (port);
 	written = parport_pc_epp_write_addr (port, buf, length, flags);
 	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
 
@@ -582,7 +590,7 @@
 	if (end < MAX_DMA_ADDRESS) {
 		/* If it would cross a 64k boundary, cap it at the end. */
 		if ((start ^ end) & ~0xffffUL)
-			maxlen = (0x10000 - start) & 0xffff;
+			maxlen = 0x10000 - (start & 0xffff);
 
 		dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length,
 						       PCI_DMA_TODEVICE);
@@ -1733,7 +1741,7 @@
 	oecr = inb (ECONTROL (pb));
 	/* Search for SMC style EPP+ECP mode */
 	outb (0x80, ECONTROL (pb));
-	
+	outb (0x04, CONTROL (pb));
 	result = parport_EPP_supported(pb);
 
 	outb (oecr, ECONTROL (pb));
@@ -2254,6 +2262,7 @@
 	boca_ioppar,
 	plx_9050,
 	afavlab_tk9902,
+	timedia_1889,
 };
 
 
@@ -2291,6 +2300,7 @@
 	/* boca_ioppar */		{ 1, { { 0, -1 }, } },
 	/* plx_9050 */			{ 2, { { 4, -1 }, { 5, -1 }, } },
 	/* afavlab_tk9902 */		{ 1, { { 0, 1 }, } },
+	/* timedia_1889 */		{ 1, { { 2, -1 }, } },
 };
 
 static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
@@ -2348,6 +2358,8 @@
 	  PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 },
 	{ PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, afavlab_tk9902 },
+	{ PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, timedia_1889 },
 	{ 0, }, /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/share.c linux/drivers/parport/share.c
--- v2.3.99-pre5/linux/drivers/parport/share.c	Tue Apr 11 15:09:18 2000
+++ linux/drivers/parport/share.c	Thu Apr 13 09:25:44 2000
@@ -104,18 +104,19 @@
 }
 
 /**
- * parport_register_driver - register a parallel port device driver
- * @drv: structure describing the driver
+ *	parport_register_driver - register a parallel port device driver
+ *	@drv: structure describing the driver
  *
- * This can be called by a parallel port device driver in order to
- * receive notifications about ports being found in the system, as
- * well as ports no longer available.
+ *	This can be called by a parallel port device driver in order
+ *	to receive notifications about ports being found in the
+ *	system, as well as ports no longer available.
  *
- * The @drv structure is allocated by the caller and must not be
- * deallocated until after calling parport_unregister_driver().
+ *	The @drv structure is allocated by the caller and must not be
+ *	deallocated until after calling parport_unregister_driver().
  *
- * Returns 0 on success.  Currently it always succeeds.
+ *	Returns 0 on success.  Currently it always succeeds.
  **/
+
 int parport_register_driver (struct parport_driver *drv)
 {
 	struct parport *port;
@@ -135,22 +136,23 @@
 }
 
 /**
- * parport_unregister_driver - deregister a parallel port device driver
- * @arg: structure describing the driver that was given to
- *       parport_register_driver()
- *
- * This should be called by a parallel port device driver that has
- * registered itself using parport_register_driver() when it is about
- * to be unloaded.
- *
- * When it returns, the driver's attach() routine will no longer be
- * called, and for each port that attach() was called for, the
- * detach() routine will hae been called.
- *
- * If the caller's attach() function can block, it is their
- * responsibility to make sure to wait for it to exit before
- * unloading.
+ *	parport_unregister_driver - deregister a parallel port device driver
+ *	@arg: structure describing the driver that was given to
+ *	      parport_register_driver()
+ *
+ *	This should be called by a parallel port device driver that
+ *	has registered itself using parport_register_driver() when it
+ *	is about to be unloaded.
+ *
+ *	When it returns, the driver's attach() routine will no longer
+ *	be called, and for each port that attach() was called for, the
+ *	detach() routine will have been called.
+ *
+ *	If the caller's attach() function can block, it is their
+ *	responsibility to make sure to wait for it to exit before
+ *	unloading.
  **/
+
 void parport_unregister_driver (struct parport_driver *arg)
 {
 	struct parport_driver *drv = driver_chain, *olddrv = NULL;
@@ -180,16 +182,17 @@
 }
 
 /**
- * parport_enumerate - return a list of the system's parallel ports
+ *	parport_enumerate - return a list of the system's parallel ports
  *
- * This returns the head of the list of parallel ports in the system.
- * The structure that is returned describes the first port in the
- * list, and its 'next' member points to the next port, or %NULL if
- * it's the last port.
+ *	This returns the head of the list of parallel ports in the
+ *	system, as a &struct parport.  The structure that is returned
+ *	describes the first port in the list, and its 'next' member
+ *	points to the next port, or %NULL if it's the last port.
  *
- * If there are no parallel ports in the system, parport_enumerate()
- * will return %NULL.
+ *	If there are no parallel ports in the system,
+ *	parport_enumerate() will return %NULL.
  **/
+
 struct parport *parport_enumerate(void)
 {
 	if (!portlist)
@@ -199,32 +202,34 @@
 }
 
 /**
- * parport_register_port - register a parallel port
- * @base: base I/O address
- * @irq: IRQ line
- * @dma: DMA channel
- * @ops: pointer to the port driver's port operations structure
- *
- * When a parallel port (lowlevel) driver finds a port that should be
- * made available to parallel port device drivers, it should call
- * parport_register_port().  The @base, @irq, and @dma parameters are
- * for the convenience of port drivers, and for ports where they
- * aren't meaningful needn't be set to anything special.  They can be
- * altered afterwards by adjusting the relevant members of the parport
- * structure that is returned and represents the port.  They should
- * not be tampered with after calling parport_announce_port, however.
- *
- * If there are parallel port device drivers in the system that have
- * registered themselves using parport_register_driver(), they are not
- * told about the port at this time; that is done by
- * parport_announce_port().
+ *	parport_register_port - register a parallel port
+ *	@base: base I/O address
+ *	@irq: IRQ line
+ *	@dma: DMA channel
+ *	@ops: pointer to the port driver's port operations structure
+ *
+ *	When a parallel port (lowlevel) driver finds a port that
+ *	should be made available to parallel port device drivers, it
+ *	should call parport_register_port().  The @base, @irq, and
+ *	@dma parameters are for the convenience of port drivers, and
+ *	for ports where they aren't meaningful needn't be set to
+ *	anything special.  They can be altered afterwards by adjusting
+ *	the relevant members of the parport structure that is returned
+ *	and represents the port.  They should not be tampered with
+ *	after calling parport_announce_port, however.
+ *
+ *	If there are parallel port device drivers in the system that
+ *	have registered themselves using parport_register_driver(),
+ *	they are not told about the port at this time; that is done by
+ *	parport_announce_port().
  *
- * The @ops structure is allocated by the caller, and must not be
- * deallocated before calling parport_unregister_port().
+ *	The @ops structure is allocated by the caller, and must not be
+ *	deallocated before calling parport_unregister_port().
  *
- * If there is no memory to allocate a new parport structure, this
- * function will return %NULL.
+ *	If there is no memory to allocate a new parport structure,
+ *	this function will return %NULL.
  **/
+
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
 				      struct parport_operations *ops)
 {
@@ -310,16 +315,17 @@
 }
 
 /**
- * parport_announce_port - tell device drivers about a parallel port
- * @port: parallel port to announce
+ *	parport_announce_port - tell device drivers about a parallel port
+ *	@port: parallel port to announce
  *
- * After a port driver has registered a parallel port with
- * parport_register_port, and performed any necessary initialisation
- * or adjustments, it should call parport_announce_port() in order to
- * notify all device drivers that have called
- * parport_register_driver().  Their attach() functions will be
- * called, with @port as the parameter.
+ *	After a port driver has registered a parallel port with
+ *	parport_register_port, and performed any necessary
+ *	initialisation or adjustments, it should call
+ *	parport_announce_port() in order to notify all device drivers
+ *	that have called parport_register_driver().  Their attach()
+ *	functions will be called, with @port as the parameter.
  **/
+
 void parport_announce_port (struct parport *port)
 {
 #ifdef CONFIG_PARPORT_1284
@@ -364,22 +370,24 @@
 }
 
 /**
- * parport_unregister_port - deregister a parallel port
- * @port: parallel port to deregister
+ *	parport_unregister_port - deregister a parallel port
+ *	@port: parallel port to deregister
  *
- * When a parallel port driver is forcibly unloaded, or a parallel
- * port becomes inaccessible, the port driver must call this function
- * in order to deal with device drivers that still want to use it.
- *
- * The parport structure associated with the port has its operations
- * structure replaced with one containing 'null' operations that
- * return errors or just don't do anything.
- *
- * Any drivers that have registered themselves using
- * parport_register_driver() are notified that the port is no longer
- * accessible by having their detach() routines called with @port as
- * the parameter.
+ *	When a parallel port driver is forcibly unloaded, or a
+ *	parallel port becomes inaccessible, the port driver must call
+ *	this function in order to deal with device drivers that still
+ *	want to use it.
+ *
+ *	The parport structure associated with the port has its
+ *	operations structure replaced with one containing 'null'
+ *	operations that return errors or just don't do anything.
+ *
+ *	Any drivers that have registered themselves using
+ *	parport_register_driver() are notified that the port is no
+ *	longer accessible by having their detach() routines called
+ *	with @port as the parameter.
  **/
+
 void parport_unregister_port(struct parport *port)
 {
 	struct parport *p;
@@ -415,70 +423,74 @@
 }
 
 /**
- * parport_register_device - register a device on a parallel port
- * @port: port to which the device is attached
- * @name: a name to refer to the device
- * @pf: preemption callback
- * @kf: kick callback (wake-up)
- * @irq_func: interrupt handler
- * @flags: registration flags
- * @handle: data for callback functions
- *
- * This function, called by parallel port device drivers, declares
- * that a device is connected to a port, and tells the system all it
- * needs to know.
- *
- * The @name is allocated by the caller and must not be deallocated
- * until the caller calls @parport_unregister_device for that device.
- *
- * The preemption callback function, @pf, is called when this device
- * driver has claimed access to the port but another device driver
- * wants to use it.  It is given @handle as its parameter, and should
- * return zero if it is willing for the system to release the port to
- * another driver on its behalf.  If it wants to keep control of the
- * port it should return non-zero, and no action will be taken.  It is
- * good manners for the driver to try to release the port at the
- * earliest opportunity after its preemption callback rejects a
- * preemption attempt.  Note that if a preemption callback is happy
- * for preemption to go ahead, there is no need to release the port;
- * it is done automatically.  This function may not block, as it may
- * be called from interrupt context.  If the device driver does not
- * support preemption, @pf can be %NULL.
- *
- * The wake-up ("kick") callback function, @kf, is called when the
- * port is available to be claimed for exclusive access; that is,
- * parport_claim() is guaranteed to succeed when called from inside
- * the wake-up callback function.  If the driver wants to claim the
- * port it should do so; otherwise, it need not take any action.  This
- * function may not block, as it may be called from interrupt context.
- * If the device driver does not want to be explicitly invited to
- * claim the port in this way, @kf can be %NULL.
- *
- * The interrupt handler, @irq_func, is called when an interrupt
- * arrives from the parallel port.  Note that if a device driver wants
- * to use interrupts it should use parport_enable_irq(), and can also
- * check the irq member of the parport structure representing the
- * port.
- *
- * The parallel port (lowlevel) driver is the one that has called
- * request_irq() and whose interrupt handler is called first.  This
- * handler does whatever needs to be done to the hardware to
- * acknowledge the interrupt (for PC-style ports there is nothing
- * special to be done).  It then tells the IEEE 1284 code about the
- * interrupt, which may involve reacting to an IEEE 1284 event
- * depending on the current IEEE 1284 phase.  After this, it calls
- * @irq_func.  Needless to say, @irq_func will be called from
- * interrupt context, and may not block.
- *
- * The %PARPORT_DEV_EXCL flag is for preventing port sharing, and so
- * should only be used when sharing the port with other device drivers
- * is impossible and would lead to incorrect behaviour.  Use it
- * sparingly!  Normally, @flags will be zero.
- *
- * This function returns a pointer to a structure that represents the
- * device on the port, or %NULL if there is not enough memory to
- * allocate space for that structure.
+ *	parport_register_device - register a device on a parallel port
+ *	@port: port to which the device is attached
+ *	@name: a name to refer to the device
+ *	@pf: preemption callback
+ *	@kf: kick callback (wake-up)
+ *	@irq_func: interrupt handler
+ *	@flags: registration flags
+ *	@handle: data for callback functions
+ *
+ *	This function, called by parallel port device drivers,
+ *	declares that a device is connected to a port, and tells the
+ *	system all it needs to know.
+ *
+ *	The @name is allocated by the caller and must not be
+ *	deallocated until the caller calls @parport_unregister_device
+ *	for that device.
+ *
+ *	The preemption callback function, @pf, is called when this
+ *	device driver has claimed access to the port but another
+ *	device driver wants to use it.  It is given @handle as its
+ *	parameter, and should return zero if it is willing for the
+ *	system to release the port to another driver on its behalf.
+ *	If it wants to keep control of the port it should return
+ *	non-zero, and no action will be taken.  It is good manners for
+ *	the driver to try to release the port at the earliest
+ *	opportunity after its preemption callback rejects a preemption
+ *	attempt.  Note that if a preemption callback is happy for
+ *	preemption to go ahead, there is no need to release the port;
+ *	it is done automatically.  This function may not block, as it
+ *	may be called from interrupt context.  If the device driver
+ *	does not support preemption, @pf can be %NULL.
+ *
+ *	The wake-up ("kick") callback function, @kf, is called when
+ *	the port is available to be claimed for exclusive access; that
+ *	is, parport_claim() is guaranteed to succeed when called from
+ *	inside the wake-up callback function.  If the driver wants to
+ *	claim the port it should do so; otherwise, it need not take
+ *	any action.  This function may not block, as it may be called
+ *	from interrupt context.  If the device driver does not want to
+ *	be explicitly invited to claim the port in this way, @kf can
+ *	be %NULL.
+ *
+ *	The interrupt handler, @irq_func, is called when an interrupt
+ *	arrives from the parallel port.  Note that if a device driver
+ *	wants to use interrupts it should use parport_enable_irq(),
+ *	and can also check the irq member of the parport structure
+ *	representing the port.
+ *
+ *	The parallel port (lowlevel) driver is the one that has called
+ *	request_irq() and whose interrupt handler is called first.
+ *	This handler does whatever needs to be done to the hardware to
+ *	acknowledge the interrupt (for PC-style ports there is nothing
+ *	special to be done).  It then tells the IEEE 1284 code about
+ *	the interrupt, which may involve reacting to an IEEE 1284
+ *	event depending on the current IEEE 1284 phase.  After this,
+ *	it calls @irq_func.  Needless to say, @irq_func will be called
+ *	from interrupt context, and may not block.
+ *
+ *	The %PARPORT_DEV_EXCL flag is for preventing port sharing, and
+ *	so should only be used when sharing the port with other device
+ *	drivers is impossible and would lead to incorrect behaviour.
+ *	Use it sparingly!  Normally, @flags will be zero.
+ *
+ *	This function returns a pointer to a structure that represents
+ *	the device on the port, or %NULL if there is not enough memory
+ *	to allocate space for that structure.
  **/
+
 struct pardevice *
 parport_register_device(struct parport *port, const char *name,
 			int (*pf)(void *), void (*kf)(void *),
@@ -581,11 +593,12 @@
 }
 
 /**
- * parport_unregister_device - deregister a device on a parallel port
- * @dev: pointer to structure representing device
+ *	parport_unregister_device - deregister a device on a parallel port
+ *	@dev: pointer to structure representing device
  *
- * This undoes the effect of parport_register_device().
+ *	This undoes the effect of parport_register_device().
  **/
+
 void parport_unregister_device(struct pardevice *dev)
 {
 	struct parport *port;
@@ -633,15 +646,17 @@
 }
 
 /**
- * parport_claim - claim access to a parallel port device
- * @dev: pointer to structure representing a device on the port
+ *	parport_claim - claim access to a parallel port device
+ *	@dev: pointer to structure representing a device on the port
  *
- * This function will not block and so can be used from interrupt
- * context.  If parport_claim() succeeds in claiming access to the
- * port it returns zero and the port is available to use.  It may fail
- * (returning non-zero) if the port is in use by another driver and
- * that driver is not willing to relinquish control of the port.
+ *	This function will not block and so can be used from interrupt
+ *	context.  If parport_claim() succeeds in claiming access to
+ *	the port it returns zero and the port is available to use.  It
+ *	may fail (returning non-zero) if the port is in use by another
+ *	driver and that driver is not willing to relinquish control of
+ *	the port.
  **/
+
 int parport_claim(struct pardevice *dev)
 {
 	struct pardevice *oldcad;
@@ -744,14 +759,15 @@
 }
 
 /**
- * parport_claim_or_block - claim access to a parallel port device
- * @dev: pointer to structure representing a device on the port
+ *	parport_claim_or_block - claim access to a parallel port device
+ *	@dev: pointer to structure representing a device on the port
  *
- * This behaves like parport_claim(), but will block if necessary to
- * wait for the port to be free.  A return value of 1 indicates that
- * it slept; 0 means that it succeeded without needing to sleep.  A
- * negative error code indicates failure.
+ *	This behaves like parport_claim(), but will block if necessary
+ *	to wait for the port to be free.  A return value of 1
+ *	indicates that it slept; 0 means that it succeeded without
+ *	needing to sleep.  A negative error code indicates failure.
  **/
+
 int parport_claim_or_block(struct pardevice *dev)
 {
 	int r;
@@ -795,13 +811,14 @@
 }
 
 /**
- * parport_release - give up access to a parallel port device
- * @dev: pointer to structure representing parallel port device
+ *	parport_release - give up access to a parallel port device
+ *	@dev: pointer to structure representing parallel port device
  *
- * This function cannot fail, but it should not be called without the
- * port claimed.  Similarly, if the port is already claimed you should
- * not try claiming it again.
+ *	This function cannot fail, but it should not be called without
+ *	the port claimed.  Similarly, if the port is already claimed
+ *	you should not try claiming it again.
  **/
+
 void parport_release(struct pardevice *dev)
 {
 	struct parport *port = dev->port->physport;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.99-pre5/linux/drivers/pci/pci.c	Wed Apr 12 10:02:34 2000
+++ linux/drivers/pci/pci.c	Wed Apr 12 09:16:31 2000
@@ -1068,6 +1068,7 @@
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_register_driver);
 EXPORT_SYMBOL(pci_unregister_driver);
+EXPORT_SYMBOL(pci_dev_driver);
 EXPORT_SYMBOL(pci_match_device);
 EXPORT_SYMBOL(pci_find_parent_resource);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.3.99-pre5/linux/drivers/pci/pci.ids	Tue Apr 11 15:09:18 2000
+++ linux/drivers/pci/pci.ids	Mon Apr 24 15:17:07 2000
@@ -4,7 +4,7 @@
 #	Maintained by Martin Mares <pci-ids@ucw.cz>
 #	If you have any new entries, send them to the maintainer.
 #
-#	$Id: pci.ids,v 1.53 2000/03/09 08:19:20 mj Exp $
+#	$Id: pci.ids,v 1.56 2000/04/17 16:11:58 mj Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -18,7 +18,8 @@
 001a  Ascend Communications, Inc.
 0033  Paradyne corp.
 003d  Lockheed Martin-Marietta Corp
-0070  Hauppage computer works Inc.
+0070  Hauppauge computer works Inc.
+0100  Ncipher Corp Ltd
 0675  Dynalink
 	1700  IS64PH ISDN Adapter
 	1702  IS64PH ISDN Adapter
@@ -34,7 +35,12 @@
 	3034  QVision 1280/p
 	4000  4000 [Triflex]
 	6010  HotPlug PCI Bridge 6010
+	7020  USB Controller
+	a0ec  Fibre Channel Host Controller
+	a0f0  Advanced System Management Controller
 	a0f3  Triflex PCI to ISA Bridge
+	a0f7  PCI Hotplug Controller
+	a0f8  USB Open Host Controller
 	ae10  Smart-2/P RAID Controller
 		0e11 4030  Smart-2/P Array Controller
 		0e11 4031  Smart-2SL Array Controller
@@ -43,13 +49,16 @@
 	ae29  MIS-L
 	ae2a  MPC
 	ae2b  MIS-E
+	ae31  System Management Controller
 	ae32  Netelligent 10/100
+	ae33  Triflex Dual EIDE Controller
 	ae34  Netelligent 10
 	ae35  Integrated NetFlex-3/P
 	ae40  Netelligent 10/100 Dual
 	ae43  ProLiant Integrated Netelligent 10/100
 	ae69  CETUS-L
 	ae6c  Northstar
+	ae6d  NorthStar CPU to PCI Bridge
 	b011  Integrated Netelligent 10/100
 	b012  Netelligent 10 T/2
 	b030  Netelligent WS 5100
@@ -66,6 +75,7 @@
 	0004  53c815
 	0005  53c810AP
 	0006  53c860
+	000a  53c1510
 	000b  53c896
 	000c  53c895
 	000d  53c885
@@ -74,6 +84,7 @@
 		1092 8760  FirePort 40 Dual SCSI Controller
 		1de1 3904  DC390F Ultra Wide SCSI Controller
 	0012  53c895a
+	0020  53c1010 Ultra3 SCSI Adapter
 	008f  53c875J
 		1092 8000  FirePort 40 SCSI Controller
 		1092 8760  FirePort 40 Dual SCSI Host Adapter
@@ -83,13 +94,24 @@
 	0901  61C102
 	1000  63C815
 1001  Initio
+	0010  PCI 1616 Measurement card with 32 digital I/O lines
+	0011  OPTO-PCI Opto-Isolated digital I/O board
+	0012  PCI-AD/DA Analogue I/O board
+	0013  PCI-OPTO-RELAIS Digital I/O board with relay outputs
+	0014  PCI-Counter/Timer Counter Timer board
+	0015  PCI-DAC416 Analogue output board
+	0016  PCI-MFB Analogue I/O board
+	0017  PROTO-3 PCI Prototyping board
 	9100  INI-9100/9100W SCSI Host
 1002  ATI Technologies Inc
 	4158  68800AX [Mach32]
 	4354  215CT [Mach64 CT]
 	4358  210888CX [Mach64 CX]
 	4554  210888ET [Mach64 ET]
+	4654  Mach64 VT
 	4742  3D Rage Pro AGP 1X/2X
+		1028 4082  Optiplex GX1 Onboard Display Adapter	
+		8086 4152  Rage 3D Pro AGP
 	4744  3D Rage Pro AGP 1X
 	4747  3D Rage Pro
 	4749  3D Rage Pro
@@ -99,17 +121,26 @@
 	474f  Rage XL
 	4750  3D Rage Pro 215GP
 	4751  3D Rage Pro 215GQ
+	4752  Rage XL
 	4753  Rage XC
 	4754  3D Rage I/II 215GT [Mach64 GT]
 	4755  3D Rage II+ 215GTB [Mach64 GTB]
 	4756  3D Rage IIC 215IIC [Mach64 GT IIC]
 	4757  3D Rage IIC AGP
+		1028 0089  Rage 3D IIC
+		1028 4082  Rage 3D IIC
+		1028 8082  Rage 3D IIC
+		1028 c082  Rage 3D IIC
 	4758  210888GX [Mach64 GX]
 	4759  3D Rage IIC
 	475a  3D Rage IIC AGP
+		1002 0087  Rage 3D IIC
 	4c42  3D Rage LT Pro AGP-133
+		0e11 b0e8  Rage 3D LT Pro
 		0e11 b10e  3D Rage LT Pro (Compaq Armada 1750)
+		1028 0085  Rage 3D LT Pro
 	4c44  3D Rage LT Pro AGP-66
+	4c46  Mobility M3 AGP 2x
 	4c47  3D Rage LT-G 215LG
 	4c49  3D Rage LT Pro
 	4c4d  3D Rage P/M Mobility AGP 2x
@@ -125,15 +156,17 @@
 	5044  Rage 128 PD
 	5045  Rage 128 PE
 	5046  Rage 128 PF
+		1002 2000  Rage Fury MAXX AGP 4x (TMDS) (VGA device)
+		1002 2001  Rage Fury MAXX AGP 4x (TMDS) (Extra device?!)
 	5047  Rage 128 PG
 	5048  Rage 128 PH
 	5049  Rage 128 PI
-	504A  Rage 128 PJ
-	504B  Rage 128 PK
-	504C  Rage 128 PL
-	504D  Rage 128 PM
-	504E  Rage 128 PN
-	504F  Rage 128 PO
+	504a  Rage 128 PJ
+	504b  Rage 128 PK
+	504c  Rage 128 PL
+	504d  Rage 128 PM
+	504e  Rage 128 PN
+	504f  Rage 128 PO
 	5050  Rage 128 PP
 	5051  Rage 128 PQ
 	5052  Rage 128 PR
@@ -150,12 +183,15 @@
 	5345  Rage 128 SE
 	5346  Rage 128 SF
 	5347  Rage 128 SG
-	534B  Rage 128 SK
-	534C  Rage 128 SL
-	534D  Rage 128 SM
+	5348  Rage 128 4x
+	534b  Rage 128 SK
+	534c  Rage 128 SL
+	534d  Rage 128 SM
+	534e  Rage 128 4x
 	5354  Mach 64 VT
 		1002 5654  Mach 64 reference
 	5654  264VT [Mach64 VT]
+		1002 5654  Mach64VT Reference
 	5655  264VT3 [Mach64 VT3]
 	5656  264VT4 [Mach64 VT4]
 1003  ULSI Systems
@@ -175,6 +211,18 @@
 	0105  82C147
 	0200  82C975
 	0280  82C925
+	0304  QSound ThunderBird PCI Audio
+		1004 0304  QSound ThunderBird PCI Audio
+		122d 1206  DSP368 Audio
+		1483 5020  XWave Thunder 3D Audio
+	0305  QSound ThunderBird PCI Audio Gameport
+		1004 0305  QSound ThunderBird PCI Audio Gameport
+		122d 1207  DSP368 Audio Gameport
+		1483 5021  XWave Thunder 3D Audio Gameport
+	0306  QSound ThunderBird PCI Audio Support Registers
+		1004 0306  QSound ThunderBird PCI Audio Support Registers
+		122d 1208  DSP368 Audio Support Registers
+		1483 5022  XWave Thunder 3D Audio Support Registers
 	0702  VAS96011 [Golden Gate II]
 1005  Avance Logic Inc. [ALI]
 	2064  ALG2032/2064
@@ -191,6 +239,9 @@
 100b  National Semiconductor Corporation
 	0001  DP83810
 	0002  87415
+	000f  OHCI Compliant FireWire Controller
+	0011  National PCI System I/O
+	0012  USB Controller
 	d001  87410
 100c  Tseng Labs Inc
 	3202  ET4000/W32p rev A
@@ -215,14 +266,15 @@
 		10b8 2001  SMC9332BDT EtherPower 10/100
 		10b8 2002  SMC9332BVT EtherPower T4 10/100
 		10b8 2003  SMC9334BDT EtherPower 10/100 (1-port)
+		1109 2400  ANA-6944A/TX Fast Ethernet
 		1112 2300  RNS2300 Fast Ethernet
 		1112 2320  RNS2320 Fast Ethernet
 		1112 2340  RNS2340 Fast Ethernet
 		1113 1207  EN-1207-TX Fast Ethernet
-		1109 2400  ANA-6944A/TX Fast Ethernet
 		1186 1100  DFE-500TX Fast Ethernet
 		1186 1112  DFE-570TX Fast Ethernet
 		1282 9100  AEF-380TXD Fast Ethernet
+		1385 1100  FA310TX Fast Ethernet
 		2646 0001  KNE100TX Fast Ethernet
 	000a  21230 Video Codec
 	000d  PBXGB [TGA2]
@@ -245,14 +297,17 @@
 		115d 0002  Cardbus Ethernet 10/100
 		1179 0203  Fast Ethernet
 		1179 0204  Cardbus Fast Ethernet
+		1186 1100  DFE-500TX Fast Ethernet
 		1186 1101  DFE-500TX Fast Ethernet
 		1186 1102  DFE-500TX Fast Ethernet
 		1266 0004  Eagle Fast EtherMAX
 		12af 0019  NetFlyer Cardbus Fast Ethernet
+		1374 0001  Cardbus Ethernet Card 10/100
 		1395 0001  10/100 Ethernet CardBus PC Card
 		8086 0001  EtherExpress PRO/100 Mobile CardBus 32
 	0021  DECchip 21052
 	0022  DECchip 21150
+	0023  DECchip 21150
 	0024  DECchip 21152
 	0025  DECchip 21153
 	0026  DECchip 21154
@@ -260,6 +315,7 @@
 	0046  DECchip 21554
 		9005 1364  Dell PowerEdge RAID Controller 2
 		9005 1365  Dell PowerEdge RAID Controller 2
+	1065  RAID Controller
 1012  Micronics Computers Inc
 1013  Cirrus Logic
 	0038  GD 7548
@@ -273,6 +329,7 @@
 	00b0  GD 5440
 	00b8  GD 5446
 	00bc  GD 5480
+		1013 00bc  CL-GD5480
 	00d0  GD 5462
 	00d2  GD 5462 [Laguna I]
 	00d4  GD 5464 [Laguna]
@@ -287,12 +344,26 @@
 	1204  GD 7541 [Nordic Light]
 	4400  CD 4400
 	6001  CS 4610/11 [CrystalClear SoundFusion Audio Accelerator]
+		1014 1010  CS4610 SoundFusion Audio Accelerator
 	6003  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
+		1013 4280  Crystal SoundFusion PCI Audio Accelerator
+	6005  Crystal CS4281 PCI Audio
+		1013 4281  Crystal CS4281 PCI Audio
+		10cf 10a8  Crystal CS4281 PCI Audio
+		10cf 10a9  Crystal CS4281 PCI Audio
+		10cf 10aa  Crystal CS4281 PCI Audio
+		10cf 10ab  Crystal CS4281 PCI Audio
+		10cf 10ac  Crystal CS4281 PCI Audio
+		10cf 10ad  Crystal CS4281 PCI Audio
+		10cf 10b4  Crystal CS4281 PCI Audio
+		1179 0001  Crystal CS4281 PCI Audio
+		14c0 000c  Crystal CS4281 PCI Audio
 1014  IBM
 	0002  PCI to MCA Bridge
 	0005  Alta Lite
 	0007  Alta MP
 	000a  Fire Coral
+	0017  CPU to PCI Bridge
 	0018  TR Auto LANstreamer
 	001b  GXT-150P
 	001d  82G2675
@@ -302,19 +373,22 @@
 	002e  ServeRAID controller
 	0036  Miami
 	003e  16/4 Token ring UTP/STP controller
-		1014 003E  Token-Ring Adapter
-		1014 00CD  Token-Ring Adapter + Wake-On-LAN
-		1014 00CE  16/4 Token-Ring Adapter 2
-		1014 00CF  16/4 Token-Ring Adapter Special
-		1014 00E4  High-Speed 100/16/4 Token-Ring Adapter
-		1014 00E5  16/4 Token-Ring Adapter 2 + Wake-On-LAN
+		1014 003e  Token-Ring Adapter
+		1014 00cd  Token-Ring Adapter + Wake-On-LAN
+		1014 00ce  16/4 Token-Ring Adapter 2
+		1014 00cf  16/4 Token-Ring Adapter Special
+		1014 00e4  High-Speed 100/16/4 Token-Ring Adapter
+		1014 00e5  16/4 Token-Ring Adapter 2 + Wake-On-LAN
 	0046  MPIC interrupt controller
+	0047  PCI to PCI Bridge
+	0048  PCI to PCI Bridge
 	0053  25 MBit ATM Controller
 	0057  MPEG PCI Bridge
-	005C  i82557B 10/100
+	005c  i82557B 10/100
 	007d  3780IDSP [MWave]
 	0095  20H2999 PCI Docking Bridge
 	00b7  256-bit Graphics Rasterizer [Fire GL1]
+		1902 00b8  Fire GL1
 	ffff  MPIC-2 interrupt controller
 1015  LSI Logic Corp of Canada
 1016  ICL Personal Systems
@@ -339,6 +413,11 @@
 	c24a  90C
 101e  American Megatrends Inc.
 	9010  MegaRAID
+	9030  EIDE Controller
+	9031  EIDE Controller
+	9032  EIDE & SCSI Controller
+	9033  SCSI Controller
+	9040  Multimedia card
 	9060  MegaRAID
 101f  PictureTel
 1020  Hitachi Computer Products
@@ -373,9 +452,16 @@
 	2000  4DWave DX
 	2001  4DWave NX
 	8400  CyberBlade/i7
+		1023 8400  CyberBlade i7 AGP
 	8420  CyberBlade/i7d
+		0e11 b15a  CyberBlade i7 AGP
 	8500  CyberBlade/i1
+	8520  CyberBlade i1
+		0e11 b16e  CyberBlade i1 AGP
+		1023 8520  CyberBlade i1 AGP
 	9320  TGUI 9320
+	9350  GUI Accelerator
+	9360  Flat panel GUI Accelerator
 	9382  Cyber 9382 [Reference design]
 	9383  Cyber 9383 [Reference design]
 	9385  Cyber 9385 [Reference design]
@@ -390,12 +476,15 @@
 	9470  TGUI 9470
 	9520  Cyber 9520
 	9525  Cyber 9525
+	9540  Cyber 9540
 	9660  TGUI 9660/968x/968x
 	9680  TGUI 9680
 	9682  TGUI 9682
 	9683  TGUI 9683
 	9685  ProVIDIA 9685
 	9750  3DIm`age 975
+		1014 9750  3DImage 9750
+		1023 9750  3DImage 9750
 	9753  TGUI 9753
 	9754  TGUI 9754
 	9759  TGUI 975
@@ -403,6 +492,7 @@
 	9785  TGUI 9785
 	9850  3DImage 9850
 	9880  Blade 3D PCI/AGP
+		1023 9880  Blade 3D
 1024  Zenith Data Systems
 1025  Acer Incorporated [ALI]
 	1435  M1435
@@ -412,11 +502,18 @@
 	1461  M1461
 	1489  M1489
 	1511  M1511
+	1512  ALI M1512 Aladdin
 	1513  M1513
+	1521  ALI M1521 Aladdin III CPU Bridge
+		10b9 1521  ALI M1521 Aladdin III CPU Bridge
+	1523  ALI M1523 ISA Bridge
+		10b9 1523  ALI M1523 ISA Bridge
 	1531  M1531 Northbridge [Aladdin IV/IV+]
 	1533  M1533 PCI-to-ISA Bridge
+		10b9 1533  ALI M1533 Aladdin IV/V ISA South Bridge
 	1535  M1535 PCI Bridge + Super I/O + FIR
 	1541  M1541 Northbridge [Aladdin V]
+		10b9 1541  ALI M1541 Aladdin V/V+ AGP+PCI North Bridge
 	1542  M1542 Northbridge [Aladdin V]
 	1543  M1543 PCI-to-ISA Bridge + Super I/O + FIR
 	1561  M1561 Northbridge [Aladdin 7]
@@ -432,12 +529,26 @@
 	3307  M3307 MPEG-I Video Controller
 	3309  M3309 MPEG-II Video w/ Software Audio Decoder
 	3321  M3321 MPEG-II Audio/Video Decoder
+	5212  ALI M4803
+	5215  ALI PCI EIDE Controller
 	5217  M5217H
 	5219  M5219
 	5225  M5225
 	5229  M5229
 	5235  M5235
+	5237  ALI M5237 PCI USB Host Controller
+	5240  EIDE Controller
+	5241  PCMCIA Bridge
+	5242  General Purpose Controller
+	5243  PCI to PCI Bridge Controller
+	5244  Floppy Disk Controller
+	5247  ALI M1541 PCI to PCI Bridge
 	5251  M5251 P1394 OHCI Controller
+	5427  ALI PCI to AGP Bridge
+	5451  ALI M5451 PCI AC-Link Controller Audio Device
+	5453  ALI M5453 PCI AC-Link Controller Modem Device
+	7101  ALI M7101 PCI PMU Power Management Controller
+		10b9 7101  ALI M7101 PCI PMU Power Management Controller
 1028  Dell Computer Corporation
 	0001  PowerEdge Expandable RAID Controller 2/Si
 	0002  PowerEdge Expandable RAID Controller 3/Di
@@ -452,8 +563,14 @@
 	0518  MGA-II [Athena]
 	0519  MGA 2064W [Millennium]
 	051a  MGA 1064SG [Mystique]
+		102b 1100  MGA-1084SG Mystique
+		102b 1200  MGA-1084SG Mystique
 		1100 102b  MGA-1084SG Mystique
+		110a 0018  Scenic Pro C5 (D1025)
 	051b  MGA 2164W [Millennium II]
+		102b 051b  MGA-2164W Millennium II
+		102b 1100  MGA-2164W Millennium II
+		102b 1200  MGA-2164W Millennium II
 	051e  MGA 1064SG [Mystique] AGP
 	051f  MGA 2164W [Millennium II] AGP
 	0520  MGA G200
@@ -475,10 +592,16 @@
 		102b ca60  Millennium G250 LE AGP
 		102b ca6c  Millennium G250 AGP
 		102b dbbc  Millennium G200 AGP
+		102b dbc2  Millennium G200 MMS (Dual G200)
+		102b dbc8  Millennium G200 MMS (Dual G200)
+		102b dbe2  Millennium G200 MMS (Quad G200)
+		102b dbe8  Millennium G200 MMS (Quad G200)
 		102b f806  Mystique G200 Video AGP
+		102b ff00  MGA-G200 AGP
 		102b ff02  Mystique G200 AGP
 		102b ff03  Millennium G200 AGP
 		102b ff04  Marvel G200 AGP
+		110a 0032  MGA-G200 AGP
 	0525  MGA G400 AGP
 		0e11 b16f  Matrox MGA-G400 AGP
 		102b 0328  Millennium G400 16Mb SDRAM
@@ -497,9 +620,16 @@
 		102b ff01  Productiva G100
 		102b ff05  Productiva G100 Multi-Monitor
 	1001  MGA G100 [Productiva] AGP
+		102b 1001  MGA-G100 AGP
+		102b ff00  MGA-G100 AGP
+		102b ff01  MGA-G100 Productiva AGP
+		102b ff03  Millennium G100 AGP
+		102b ff04  MGA-G100 AGP
 		102b ff05  MGA-G100 Productiva AGP Multi-Monitor
+		110a 001e  MGA-G100 AGP
 	2007  MGA Mistral
 	4536  VIA Framegrabber
+	6573  Shark 10/100 Multiport SwitchNIC
 102c  Chips and Technologies
 	00b8  F64310
 	00c0  F69000 HiQVideo
@@ -532,12 +662,16 @@
 	0003  ATM Controller
 	0004  R4000 PCI Bridge
 	0005  PCI to 486-like bus Bridge
+	0006  GUI Accelerator
 	0007  PCI to UX-Bus Bridge
+	0008  GUI Accelerator
+	0009  GUI Accelerator for W98
 	001a  [Nile II]
 	0021  Vrc4373 [Nile I]
 	0029  PowerVR PCX1
 	002a  PowerVR 3D
 	0035  USB
+	003e  NAPCCARD Cardbus Controller
 	0046  PowerVR PCX2 [midas]
 	005a  Vrc5074 [Nile 4]
 	0063  Firewarden
@@ -565,7 +699,9 @@
 	0006  85C501/2/3
 	0008  85C503/5513
 	0009  ACPI
+	0018  SiS85C503/5513 (LPC Bridge)
 	0200  5597/5598 VGA
+		1039 0000  SiS5597 SVGA (Shared RAM)
 	0204  82C204
 	0205  SG86C205
 	0406  85C501/2
@@ -577,34 +713,81 @@
 	0620  620 Host
 	0630  630 Host
 	0900  SiS900 10/100 Ethernet
+		1039 0900  SiS900 10/100 Ethernet Adapter
 	3602  83C602
 	5107  5107
+	5300  SiS540 PCI Display Adapter
+	5401  486 PCI Chipset
 	5511  5511/5512
 	5513  5513 [IDE]
+		1039 5513  SiS5513 EIDE Controller (A,B step)
 	5517  5517
 	5571  5571
+	5581  5581 Pentium Chipset
+	5582  5582
 	5591  5591/5592 Host
+	5596  5596 Pentium Chipset
 	5597  5597 [SiS5582]
 	5600  5600 Host
 	6204  Video decoder & MPEG interface
+	6205  VGA Controller
 	6236  6236 3D-AGP
+	6300  SiS630 GUI Accelerator+3D
 	6306  6306 3D-AGP
+		1039 6306  SiS530,620 GUI Accelerator+3D
 	6326  86C326
+		1039 6326  SiS6326 GUI Accelerator
 		1092 0a50  SpeedStar A50
 		1092 0a70  SpeedStar A70
 		1092 4910  SpeedStar A70 
 		1092 4920  SpeedStar A70 
+		1569 6326  SiS6326 GUI Accelerator
 	7001  7001
 	7007  OHCI Compliant FireWire Controller
+	7016  SiS7016 10/100 Ethernet Adapter
+		1039 7016  SiS7016 10/100 Ethernet Adapter
+	7018  SiS PCI Audio Accelerator
+		1014 01b6  SiS PCI Audio Accelerator
+		1014 01b7  SiS PCI Audio Accelerator
+		1019 7018  SiS PCI Audio Accelerator
+		1025 000e  SiS PCI Audio Accelerator
+		1025 0018  SiS PCI Audio Accelerator
+		1039 7018  SiS PCI Audio Accelerator
+		1043 800b  SiS PCI Audio Accelerator
+		1054 7018  SiS PCI Audio Accelerator
+		107d 5330  SiS PCI Audio Accelerator
+		107d 5350  SiS PCI Audio Accelerator
+		1170 3209  SiS PCI Audio Accelerator
+		1462 400a  SiS PCI Audio Accelerator
+		14a4 2089  SiS PCI Audio Accelerator
+		14cd 2194  SiS PCI Audio Accelerator
+		14ff 1100  SiS PCI Audio Accelerator
+		152d 8808  SiS PCI Audio Accelerator
+		1558 1103  SiS PCI Audio Accelerator
+		1558 2200  SiS PCI Audio Accelerator
+		1563 7018  SiS PCI Audio Accelerator
+		15c5 0111  SiS PCI Audio Accelerator
+		270f a171  SiS PCI Audio Accelerator
+		a0a0 0022  SiS PCI Audio Accelerator
 103a  Seiko Epson Corporation
 103b  Tatung Co. of America
 103c  Hewlett-Packard Company
 	1030  J2585A
 	1031  J2585B
+		103c 1040  J2973A DeskDirect 10BaseT NIC
+		103c 1041  J2585B DeskDirect 10/100VG NIC
+		103c 1042  J2970A DeskDirect 10BaseT/2 NIC
 	1040  J2973A DeskDirect 10BaseT NIC
 	1041  J2585B DeskDirect 10/100 NIC
 	1042  J2970A DeskDirect 10BaseT/2 NIC
 	1064  79C970 PCnet Ethernet Controller
+	10c1  NetServer Smart IRQ Router
+	10ed  TopTools Remote Control
+	1200  82557B 10/100 NIC
+	1219  NetServer PCI Hot-Plug Controller
+	121a  NetServer SMIC Controller
+	121b  NetServer Legacy COM Port Decoder
+	121c  NetServer PCI COM Port Decoder
 	2910  E2910A
 	2925  E2925A
 103e  Solliday Engineering
@@ -640,8 +823,10 @@
 	c822  82C822
 	c824  82C824
 	c825  82C825 [Firebridge 2]
+	c832  82C832
 	c861  82C861
 	c895  82C895
+	c935  EV1935 ECTIVA MachOne PCI Audio
 	d568  82C825 [Firebridge 2]
 1046  IPC Corporation, Ltd.
 1047  Genoa Systems Corp
@@ -678,11 +863,13 @@
 		1097 3d01  Jeronimo Pro
 		3d3d 0100  Reference Permedia 2 3D
 	8000  PCILynx/PCILynx2 IEEE 1394 Link Layer Controller
-		e4bf 1010 CF1-1-SNARE
-		e4bf 1020 CF1-2-SNARE 
+		e4bf 1010  CF1-1-SNARE
+		e4bf 1020  CF1-2-SNARE 
 	8009  OHCI Compliant FireWire Controller
 	8019  TSB12LV23 OHCI Compliant IEEE-1394 Controller
-		e4bf 1010 CF2-1-CYMBAL
+		11bd 000a  Studio DV500-1394
+		11bd 000e  Studio DV
+		e4bf 1010  CF2-1-CYMBAL
 	a001  TDC1570
 	a100  TDC1561
 	ac10  PCI1050
@@ -701,15 +888,24 @@
 	ac1e  PCI1211
 	ac1f  PCI1251B
 	ac20  TI 2030
+	ac30  PCI1260 PC card Cardbus Controller
+	ac40  PCI4450 PC card Cardbus Controller
+	ac41  PCI4410 PC card Cardbus Controller
+	ac42  PCI4451 PC card Cardbus Controller
+	ac50  PCI1410 PC card Cardbus Controller
 	ac51  PCI1420
+	ac52  PCI1451 PC card Cardbus Controller
+	ac53  PCI1421 PC card Cardbus Controller
 	fe00  FireWire Host Controller
 	fe03  12C01A FireWire Host Controller
 104d  Sony Corporation
-	8039  CXD3222 iLINK Controller
+	8009  CXD1947Q i.LINK Controller
+	8039  CXD3222 i.LINK Controller
 	8056  Rockwell HCF 56K modem
 104e  Oak Technology, Inc
 	0017  OTI-64017
 	0107  OTI-107 [Spitfire]
+	0109  Video Adapter
 	0111  OTI-64111 [Spitfire]
 	0217  OTI-64217
 	0317  OTI-64317
@@ -719,35 +915,48 @@
 	0001  W83769F
 	0105  W82C105
 	0840  W89C840
+		1050 0001  W89C840 Ethernet Adapter
+		1050 0840  W89C840 Ethernet Adapter
 	0940  W89C940
 	5a5a  W89C940F
 	9970  W9970CF
 1051  Anigma, Inc.
+1052  ?Young Micro Systems
 1053  Young Micro Systems
 1054  Hitachi, Ltd
 1055  EFAR Microsystems
 1056  ICL
-# Motorola made a mistake and used this value, please duplicate Moto
-# entries here -- Cort
-1507  Motorola
-	0001  MPC105 [Eagle]
-	0002  MPC106 [Grackle]
-	0003  MPC8240 [Kahlua]
-	0100  MC145575 [HFC-PCI]
-	0431  KTI829c 100VG
-	4801  Raven
-	4802  Falcon
-	4803  Hawk
-	4806  CPX8216
+# Motorola made a mistake and used 1507 instead of 1057 in some chips.
+# Please look at the 1507 entry as well when updating this.
 1057  Motorola
 	0001  MPC105 [Eagle]
 	0002  MPC106 [Grackle]
 	0100  MC145575 [HFC-PCI]
 	0431  KTI829c 100VG
+	1801  Audio I/O Controller (MIDI)
+		ecc0 0030  Layla
 	4801  Raven
 	4802  Falcon
 	4803  Hawk
 	4806  CPX8216
+	5600  SM56 PCI Modem
+		1057 0300  SM56 PCI Speakerphone Modem
+		1057 0301  SM56 PCI Voice Modem
+		1057 0302  SM56 PCI Fax Modem
+		1057 5600  SM56 PCI Voice modem
+		13d2 0300  SM56 PCI Speakerphone Modem
+		13d2 0301  SM56 PCI Voice modem
+		13d2 0302  SM56 PCI Fax Modem
+		1436 0300  SM56 PCI Speakerphone Modem
+		1436 0301  SM56 PCI Voice modem
+		1436 0302  SM56 PCI Fax Modem
+		144f 100c  SM56 PCI Fax Modem
+		1494 0300  SM56 PCI Speakerphone Modem
+		1494 0301  SM56 PCI Voice modem
+		14c8 0300  SM56 PCI Speakerphone Modem
+		14c8 0302  SM56 PCI Fax Modem
+		1668 0300  SM56 PCI Speakerphone Modem
+		1668 0302  SM56 PCI Fax Modem
 1058  Electronics & Telecommunications RSH
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
@@ -784,6 +993,7 @@
 	0891  UM8891A
 	1001  UM886A
 	673a  UM8886BF
+	673b  EIDE Master/DMA
 	8710  UM8710
 	886a  UM8886A
 	8881  UM8881F
@@ -795,6 +1005,7 @@
 	9026  UM9026
 	e881  UM8881N
 	e886  UM8886N
+	e88a  UM8886N
 	e891  UM8891N
 1061  I.I.T.
 	0001  AGX016
@@ -828,6 +1039,8 @@
 	0010  Heathrow Mac I/O
 	0017  Paddington Mac I/O
 106c  Hyundai Electronics America
+	8801  Dual Pentium ISA/PCI Motherboard
+	8802  PowerPC ISA/PCI Motherboard
 	8803  Dual Window Graphics Accelerator
 	8804  LAN Controller
 	8805  100-BaseT LAN
@@ -838,13 +1051,29 @@
 1071  Mitac
 1072  GIT Co Ltd
 1073  Yamaha Corporation
+	0001  3D GUI Accelerator
 	0002  YGV615 [RPA3 3D-Graphics Controller]
 	0003  YMF-740
 	0004  YMF-724
-	000C  YMF-740C [DS-1L Audio Controller]
-	000D  YMF-724F [DS-1 Audio Controller]
+		1073 0004  YMF724-Based PCI Audio Adapter
+	0005  DS1 Audio
+		1073 0005  DS-XG PCI Audio CODEC
+	0006  DS1 Audio
+	0008  DS1 Audio
+		1073 0008  DS-XG PCI Audio CODEC
+	000a  DS1L Audio
+		1073 0004  DS-XG PCI Audio CODEC
+		1073 000a  DS-XG PCI Audio CODEC
+	000c  YMF-740C [DS-1L Audio Controller]
+		107a 000c  DS-XG PCI Audio CODEC
+	000d  YMF-724F [DS-1 Audio Controller]
+		1073 000d  DS-XG PCI Audio CODEC
 	0010  YMF-744B [DS-1S Audio Controller]
+		1073 0006  DS-XG PCI Audio CODEC
+		1073 0010  DS-XG PCI Audio CODEC
 	0012  YMF-754 [DS-1E Audio Controller]
+		1073 0012  DS-XG PCI Audio Codec
+	0020  DS-1 Audio
 1074  NexGen Microsystems
 	4e78  82c500/1
 1075  Advanced Integrations Research
@@ -899,18 +1128,24 @@
 	0010  VME Bridge Model 618
 	3000  VME Bridge Model 2706
 108c  Oakleigh Systems Inc.
-108d Olicom
+108d  Olicom
 	0001  Token-Ring 16/4 PCI Adapter (3136/3137)
 	0002  16/4 Token Ring
 	0004  RapidFire 3139 Token-Ring 16/4 PCI Adapter
+		108d 0004  OC-3139/3140 RapidFire Token-Ring 16/4 Adapter
 	0005  GoCard 3250 Token-Ring 16/4 CardBus PC Card
 	0006  OC-3530 RapidFire Token-Ring 100
 	0007  RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter
+		108d 0007  OC-3141 RapidFire Token-Ring 16/4 Adapter
 	0008  RapidFire 3540 HSTR 100/16/4 PCI Adapter
+		108d 0008  OC-3540 RapidFire HSTR 100/16/4 Adapter
 	0011  OC-2315
 	0012  OC-2325
 	0013  OC-2183/2185
 	0014  OC-2326
+	0019  OC-2327/2250 10/100 Ethernet Adapter
+		108d 0016  OC-2327 Rapidfire 10/100 Ethernet Adapter
+		108d 0017  OC-2250 GoCard 10/100 Ethernet Adapter
 	0021  OC-6151/6152 [RapidFire ATM 155]
 	0022  ATM Adapter
 108e  Sun Microsystems Computer Corp.
@@ -918,6 +1153,7 @@
 	1000  EBUS
 	1001  Happy Meal
 	5000  Simba Advanced PCI Bridge
+	5043  SunPCI Co-processor
 	8000  PCI Bus Module
 	a000  Ultra IIi
 108f  Systemsoft
@@ -928,7 +1164,7 @@
 	0040  3D graphics frame buffer
 	0041  3D graphics frame buffer
 	0060  Proprietary bus bridge
-	00E4  Powerstorm 4D50T
+	00e4  Powerstorm 4D50T
 	0720  Motion JPEG codec
 1092  Diamond Multimedia Systems
 	00a0  Speedstar Pro SE
@@ -992,15 +1228,94 @@
 109e  Brooktree Corporation
 	0350  Bt848 TV with DMA push
 	0351  Bt849A Video capture
+	036c  Bt879(??) Video Capture
+		13e9 0070  Win/TV (Video Section)
 	036e  Bt878
+		127a 0001  Bt878 Mediastream Controller NTSC
+		127a 0002  Bt878 Mediastream Controller PAL BG
+		127a 0003  Bt878a Mediastream Controller PAL BG
+		127a 0048  Bt878/832 Mediastream Controller
+		144f 3000  MagicTView CPH060 - Video
+		14f1 0001  Bt878 Mediastream Controller NTSC
+		14f1 0002  Bt878 Mediastream Controller PAL BG
+		14f1 0003  Bt878a Mediastream Controller PAL BG
+		14f1 0048  Bt878/832 Mediastream Controller
 		1851 1850  FlyVideo'98 - Video
 		1851 1851  FlyVideo II
 		1852 1852  FlyVideo'98 - Video (with FM Tuner)
 	036f  Bt879
+		127a 0044  Bt879 Video Capture NTSC
+		127a 0122  Bt879 Video Capture PAL I
+		127a 0144  Bt879 Video Capture NTSC
+		127a 0222  Bt879 Video Capture PAL BG
+		127a 0244  Bt879a Video Capture NTSC
+		127a 0322  Bt879 Video Capture NTSC
+		127a 0422  Bt879 Video Capture NTSC
+		127a 1122  Bt879 Video Capture PAL I
+		127a 1222  Bt879 Video Capture PAL BG
+		127a 1322  Bt879 Video Capture NTSC
+		127a 1522  Bt879a Video Capture PAL I
+		127a 1622  Bt879a Video Capture PAL BG
+		127a 1722  Bt879a Video Capture NTSC
+		14f1 0044  Bt879 Video Capture NTSC
+		14f1 0122  Bt879 Video Capture PAL I
+		14f1 0144  Bt879 Video Capture NTSC
+		14f1 0222  Bt879 Video Capture PAL BG
+		14f1 0244  Bt879a Video Capture NTSC
+		14f1 0322  Bt879 Video Capture NTSC
+		14f1 0422  Bt879 Video Capture NTSC
+		14f1 1122  Bt879 Video Capture PAL I
+		14f1 1222  Bt879 Video Capture PAL BG
+		14f1 1322  Bt879 Video Capture NTSC
+		14f1 1522  Bt879a Video Capture PAL I
+		14f1 1622  Bt879a Video Capture PAL BG
+		14f1 1722  Bt879a Video Capture NTSC
 		1851 1850  FlyVideo'98 - Video	
 		1851 1851  FlyVideo II
 		1852 1852  FlyVideo'98 - Video (with FM Tuner)
+	0370  Bt880 Video Capture
+		1851 1850  FlyVideo'98
+		1851 1851  FlyVideo'98 EZ - video
+		1852 1852  FlyVideo'98 (with FM Tuner)
 	0878  Bt878
+		127a 0001  Bt878 Video Capture (Audio Section)
+		127a 0002  Bt878 Video Capture (Audio Section)
+		127a 0003  Bt878 Video Capture (Audio Section)
+		127a 0048  Bt878 Video Capture (Audio Section)
+		13e9 0070  Win/TV (Audio Section)
+		144f 3000  MagicTView CPH060 - Audio
+		14f1 0001  Bt878 Video Capture (Audio Section)
+		14f1 0002  Bt878 Video Capture (Audio Section)
+		14f1 0003  Bt878 Video Capture (Audio Section)
+		14f1 0048  Bt878 Video Capture (Audio Section)
+	0879  Bt879 Video Capture (Audio Section)
+		127a 0044  Bt879 Video Capture (Audio Section)
+		127a 0122  Bt879 Video Capture (Audio Section)
+		127a 0144  Bt879 Video Capture (Audio Section)
+		127a 0222  Bt879 Video Capture (Audio Section)
+		127a 0244  Bt879 Video Capture (Audio Section)
+		127a 0322  Bt879 Video Capture (Audio Section)
+		127a 0422  Bt879 Video Capture (Audio Section)
+		127a 1122  Bt879 Video Capture (Audio Section)
+		127a 1222  Bt879 Video Capture (Audio Section)
+		127a 1322  Bt879 Video Capture (Audio Section)
+		127a 1522  Bt879 Video Capture (Audio Section)
+		127a 1622  Bt879 Video Capture (Audio Section)
+		127a 1722  Bt879 Video Capture (Audio Section)
+		14f1 0044  Bt879 Video Capture (Audio Section)
+		14f1 0122  Bt879 Video Capture (Audio Section)
+		14f1 0144  Bt879 Video Capture (Audio Section)
+		14f1 0222  Bt879 Video Capture (Audio Section)
+		14f1 0244  Bt879 Video Capture (Audio Section)
+		14f1 0322  Bt879 Video Capture (Audio Section)
+		14f1 0422  Bt879 Video Capture (Audio Section)
+		14f1 1122  Bt879 Video Capture (Audio Section)
+		14f1 1222  Bt879 Video Capture (Audio Section)
+		14f1 1322  Bt879 Video Capture (Audio Section)
+		14f1 1522  Bt879 Video Capture (Audio Section)
+		14f1 1622  Bt879 Video Capture (Audio Section)
+		14f1 1722  Bt879 Video Capture (Audio Section)
+	0880  Bt880 Video Capture (Audio Section)
 	2115  BtV 2115 Mediastream controller
 	2125  BtV 2125 Mediastream controller
 	2164  BtV 2164
@@ -1108,35 +1423,75 @@
 	0006  16/4 Cardbus Adapter
 		10b6 0006  16/4 CardBus Adapter
 	0007  Presto PCI Adapter
+		10b6 0007  Presto PCI
 	0009  Smart 100/16/4 PCI-HS Ringnode
+		10b6 0009  Smart 100/16/4 PCI-HS Ringnode
 	000a  Smart 100/16/4 PCI Ringnode
+		10b6 000a  Smart 100/16/4 PCI Ringnode
 	000b  16/4 CardBus Adapter Mk2
+		10b6 000b  16/4 Cardbus Adapter Mk2
 	1000  Collage 25 ATM Adapter
 	1001  Collage 155 ATM Server Adapter
 10b7  3Com Corporation
 	0001  3c985 1000BaseSX
 	3390  Token Link Velocity
 	3590  3c359 TokenLink Velocity XL
+		10b7 3590  TokenLink Velocity XL Adapter
+	4500  3c450 Cyclone/unknown
+	5055  3c555 Laptop Hurricane
 	5057  3c575 [Megahertz] 10/100 LAN CardBus
+		10b7 5a57  3C575 Megahertz 10/100 LAN Cardbus PC Card
 	5157  3c575 [Megahertz] 10/100 LAN CardBus
+		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
+	5257  3CCFE575CT Cyclone CardBus
 	5900  3c590 10BaseT [Vortex]
+	5920  3c592 EISA 10mbps Demon/Vortex
 	5950  3c595 100BaseTX [Vortex]
 	5951  3c595 100BaseT4 [Vortex]
 	5952  3c595 100Base-MII [Vortex]
+	5970  3c597 EISA Fast Demon/Vortex
+	6560  3CCFE656 Cyclone CardBus
+	6562  3CCFEM656 Cyclone CardBus
+	7646  3cSOHO100-TX Hurricane
 	8811  Token ring
 	9000  3c900 10BaseT [Boomerang]
 	9001  3c900 Combo [Boomerang]
 	9004  3c900B-TPO [Etherlink XL TPO]
+		10b7 9004  3C900B-TPO Etherlink XL TPO 10Mb
 	9005  3c900B-Combo [Etherlink XL Combo]
+		10b7 9005  3C900B-Combo Etherlink XL Combo
 	9006  3c900B-TPC [Etherlink XL TPC]
-	900A  3c900B-FL [Etherlink XL FL]
+	900a  3c900B-FL [Etherlink XL FL]
 	9050  3c905 100BaseTX [Boomerang]
 	9051  3c905 100BaseT4
 	9055  3c905B 100BaseTX [Cyclone]
+		1028 0080  3C905B Fast Etherlink XL 10/100
+		1028 0081  3C905B Fast Etherlink XL 10/100
+		1028 0082  3C905B Fast Etherlink XL 10/100
+		1028 0083  3C905B Fast Etherlink XL 10/100
+		1028 0084  3C905B Fast Etherlink XL 10/100
+		1028 0085  3C905B Fast Etherlink XL 10/100
+		1028 0086  3C905B Fast Etherlink XL 10/100
+		1028 0087  3C905B Fast Etherlink XL 10/100
+		1028 0088  3C905B Fast Etherlink XL 10/100
+		1028 0089  3C905B Fast Etherlink XL 10/100
+		1028 0090  3C905B Fast Etherlink XL 10/100
+		1028 0091  3C905B Fast Etherlink XL 10/100
+		1028 0092  3C905B Fast Etherlink XL 10/100
+		1028 0093  3C905B Fast Etherlink XL 10/100
+		1028 0094  3C905B Fast Etherlink XL 10/100
+		1028 0095  3C905B Fast Etherlink XL 10/100
+		1028 0096  3C905B Fast Etherlink XL 10/100
+		1028 0097  3C905B Fast Etherlink XL 10/100
+		1028 0098  3C905B Fast Etherlink XL 10/100
+		1028 0099  3C905B Fast Etherlink XL 10/100
+		10b7 9055  3C905B Fast Etherlink XL 10/100
 	9058  3c905B-Combo [Deluxe Etherlink XL 10/100]
-	905A  3c905B-FX [Fast Etherlink XL FX 10/100]
+	905a  3c905B-FX [Fast Etherlink XL FX 10/100]
 	9200  3c905C-TX [Fast Etherlink]
+		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
 	9800  3c980-TX [Fast Etherlink XL Server Adapter]
+		10b7 9800  3c980-TX Fast Etherlink XL Server Adapter
 10b8  Standard Microsystems Corp [SMC]
 	0005  83C170QF
 		1055 e000  LANEPIC
@@ -1147,11 +1502,20 @@
 		10b8 a016  EtherPower II 10/100
 		10b8 a017  EtherPower II 10/100
 	0006  LANEPIC
+		1055 e100  LANEPIC Cardbus Fast Ethernet Adapter
+		1055 e102  LANEPIC Cardbus Fast Ethernet Adapter
+		1055 e300  LANEPIC Cardbus Fast Ethernet Adapter
+		1055 e302  LANEPIC Cardbus Fast Ethernet Adapter
+		10b8 a012  LANEPIC Cardbus Fast Ethernet Adapter
+		13a2 8002  LANEPIC Cardbus Fast Ethernet Adapter
+		13a2 8006  LANEPIC Cardbus Fast Ethernet Adapter
 	1000  FDC 37c665
 	1001  FDC 37C922
 	a011  83C170QF
 	b106  SMC34C90
 10b9  Acer Laboratories Inc. [ALi]
+	0111  C-Media CMI8738/C3DX Audio Device (OEM)
+		10b9 0111  C-Media CMI8738/C3DX Audio Device (OEM)
 	1435  M1435
 	1445  M1445
 	1449  M1449
@@ -1162,12 +1526,18 @@
 	1512  M1512 [Aladdin]
 	1513  M1513 [Aladdin]
 	1521  M1521 [Aladdin III]
+		10b9 1521  ALI M1521 Aladdin III CPU Bridge
 	1523  M1523
+		10b9 1523  ALI M1523 ISA Bridge
 	1531  M1531 [Aladdin IV]
 	1533  M1533 PCI to ISA Bridge [Aladdin IV]
+		10b9 1533  ALI M1533 Aladdin IV ISA Bridge
 	1541  M1541
+		10b9 1541  ALI M1541 Aladdin V/V+ AGP System Controller
 	1543  M1543
 	1621  M1621
+	1631  ALI M1631 PCI North Bridge Aladdin Pro III
+	1641  ALI M1641 PCI North Bridge Aladdin Pro IV
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -1187,6 +1557,7 @@
 	5243  M5243
 	5247  M5247
 	7101  M7101 PMU
+		10b9 7101  ALI M7101 Power Management Controller
 10ba  Mitsubishi Electric Corp.
 	0301  AccelGraphics AccelECLIPSE
 10bb  Dapha Electronics Corporation
@@ -1209,10 +1580,40 @@
 	0002  NM2090 [MagicGraph 128V]
 	0003  NM2093 [MagicGraph 128ZV]
 	0004  NM2160 [MagicGraph 128XD]
-	0005  [MagicGraph 256AV]
-	0006  [MagicGraph 256ZX]
+		1014 00ba  MagicGraph 128XD
+		1025 1007  MagicGraph 128XD
+		1028 0074  MagicGraph 128XD
+		1028 0075  MagicGraph 128XD
+		1028 007d  MagicGraph 128XD
+		1028 007e  MagicGraph 128XD
+		1033 802f  MagicGraph 128XD
+		104d 801b  MagicGraph 128XD
+		104d 802f  MagicGraph 128XD
+		104d 830b  MagicGraph 128XD
+		10ba 0e00  MagicGraph 128XD
+		10c8 0004  MagicGraph 128XD
+		10cf 1029  MagicGraph 128XD
+		10f7 8308  MagicGraph 128XD
+		10f7 8309  MagicGraph 128XD
+		10f7 830b  MagicGraph 128XD
+		10f7 830d  MagicGraph 128XD
+		10f7 8312  MagicGraph 128XD
+	0005  [MagicMedia 256AV]
+	0006  NM2360 [MagicMedia 256ZX]
 	0083  [MagicGraph 128ZV Plus]
-	8005  [MagicMedia 256AV]
+	8005  [MagicMedia 256AV Audio]
+		0e11 b0d1  MagicMedia 256AV Audio Device on Discovery
+		0e11 b126  MagicMedia 256AV Audio Device on Durango
+		1014 00dd  MagicMedia 256AV Audio Device on BlackTip Thinkpad
+		1025 1003  MagicMedia 256AV Audio Device on TravelMate 720
+		1028 008f  MagicMedia 256AV Audio Device on Colorado Inspiron
+		103c 0007  MagicMedia 256AV Audio Device on Voyager II
+		103c 0008  MagicMedia 256AV Audio Device on Voyager III
+		103c 000d  MagicMedia 256AV Audio Device on Omnibook 900
+		10c8 8005  MagicMedia 256AV Audio Device on FireAnt
+		110a 8005  MagicMedia 256AV Audio Device
+		14c0 0004  MagicMedia 256AV Audio Device
+	8006  NM2360 [MagicMedia 256ZX Audio]
 10c9  Dataexpert Corporation
 10ca  Fujitsu Microelectr., Inc.
 10cb  Omron Corporation
@@ -1221,6 +1622,7 @@
 	1100  ASC1100
 	1200  ASC1200 [(abp940) Fast SCSI-II]
 	1300  ABP940-U / ABP960-U
+		10cd 1310  ASC1300 SCSI Adapter
 	2300  ABP940-UW
 10ce  Radius
 10cf  Citicorp TTI
@@ -1258,7 +1660,6 @@
 		1043 0200  V3400 TNT
 		1092 0550  Viper V550
 		1092 0552  Viper V550
-		1102 1015  Graphics Blaster CT6710
 		1092 4804  Viper V550 
 		1092 4808  Viper V550 
 		1092 4810  Viper V550
@@ -1269,31 +1670,70 @@
 		1092 4904  Viper V550 
 		1092 4914  Viper V550 
 		1092 8225  Viper V550
+		10de 0020  Riva TNT
+		1102 1015  Graphics Blaster CT6710
+		1102 1016  Graphics Blaster RIVA TNT
 	0028  Riva TnT2 [NV5]
 		1043 0200  AGP-V3800 SGRAM
+		1043 0201  AGP-V3800 SDRAM
+		1043 0205  PCI-V3800
+		1043 4000  AGP-V3800PRO
 		1092 4804  Viper V770
 		1092 4a00  Viper V770
 		1092 4a02  Viper V770 Ultra
 		1092 6a02  Viper V770 Ultra
 		1092 7a02  Viper V770 Ultra
+		10de 0005  RIVA TNT2 Pro
 		1102 1020  3D Blaster RIVA TNT2
+		1102 1026  3D Blaster RIVA TNT2 Digital
 		14af 5810  Maxi Gamer Xentor
 	0029  Riva TnT2 Ultra [NV5]
 		1043 0200  AGP-V3800 Deluxe
+		1043 0201  AGP-V3800 Ultra SDRAM
+		1043 0205  PCI-V3800 Ultra
 		1102 1021  3D Blaster RIVA TNT2 Ultra
+		1102 1029  3D Blaster RIVA TNT2 Ultra
+		1102 102f  3D Blaster RIVA TNT2 Ultra
 		14af 5820  Maxi Gamer Xentor 32
 	002a  Riva TnT2 [NV5]
 	002b  Riva TnT2 [NV5]
 	002c  Vanta [NV6]
 		1043 0200  AGP-V3800 Combat SDRAM
+		1043 0201  AGP-V3800 Combat
 		1092 6820  Viper V730
+		1102 1031  CT6938 VANTA 8MB
+		1102 1034  CT6894 VANTA 16MB
 		14af 5008  Maxi Gamer Phoenix 2
 	002d  Vanta [NV6]
 		1043 0200  AGP-V3800M
+		1043 0201  AGP-V3800M
+		1102 1023  CT6892 RIVA TNT2 Value
+		1102 1024  CT6932 RIVA TNT2 Value 32Mb
+		1102 102c  CT6931 RIVA TNT2 Value (Jumper)
+		1462 8808  MSI-8808
 	002e  Vanta [NV6]
 	002f  Vanta [NV6]
 	00a0  Riva TNT2
 		14af 5810  Maxi Gamer Xentor
+	0100  GeForce 256
+		1043 0200  AGP-V6600 SGRAM
+		1043 0201  AGP-V6600 SDRAM
+		1043 4008  AGP-V6600 SGRAM
+		1043 4009  AGP-V6600 SDRAM
+		1102 102d  CT6941 GeForce 256
+	0101  GeForce 256 DDR
+		1043 0202  AGP-V6800 DDR
+		1043 400a  AGP-V6800 DDR SGRAM
+		1043 400b  AGP-V6800 DDR SDRAM
+		1102 102e  CT6971 GeForce 256 DDR
+	0103  Quadro (GeForce 256 GL)
+	0110  NV11
+	0111  NV11 DDR
+	0113  NV11 GL
+	0150  NV15 (Geforce2 GTS)
+	0151  NV15 DDR (Geforce2 GTS)
+	0152  NV15 Bladerunner (Geforce2 GTS)
+	0153  NV15 GL (Quadro2)
 10df  Emulex Corporation
 	10df  Light Pulse Fibre Channel Adapter
 	1ae5  LP6000 Fibre Channel Host Adapter
@@ -1327,6 +1767,9 @@
 	8088  Kingsberg Spacetec Format Synchronizer
 	8089  Kingsberg Spacetec Serial Output Board
 	809c  S5933_HEPC3
+	80d7  PCI-9112
+	80d9  PCI-9118
+	80da  PCI-9812
 	811a  PCI-IEEE1355-DS-DE Interface
 	8170  S5933 "Matchmaker" [PCI Chipset Development Tool]
 10e9  Alps Electric Co., Ltd.
@@ -1349,6 +1792,9 @@
 		1186 0300  DE-528
 		1259 2400  AT-2400
 	8129  RTL-8129
+		10ec 8129  RT8129 Fast Ethernet Adapter
+	8138  RT8139 (B/C) Cardbus Fast Ethernet Adapter
+		10ec 8138  RT8139 (B/C) Fast Ethernet Adapter
 	8139  RTL-8139
 		1025 8920  ALN-325
 		1025 8921  ALN-325
@@ -1407,12 +1853,16 @@
 		1102 0020  CT4850 SBLive! Value
 		1102 0021  CT4620 SBLive!
 		1102 002f  SBLive! mainboard implementation 
+		1102 4001  E-mu APS
 		1102 8022  CT4780 SBLive! Value
+		1102 8023  CT4790 SoundBlaster PCI512
 		1102 8024  CT4760 SBLive!
+		1102 8025  SBLive! Mainboard Implementation
 		1102 8026  CT4830 SBLive! Value
 		1102 8027  CT4832 SBLive! Value
 		1102 8031  CT4831 SBLive! Value
 		1102 8040  CT4760 SBLive!
+		1102 8051  CT4850 SBLive! Value
 	7002  SB Live!
 		1102 0020  Gameport Joystick
 1103  Triones Technologies, Inc.
@@ -1424,7 +1874,6 @@
 1106  VIA Technologies, Inc.
 	0391  VT8371 [KX133]
 	0501  VT8501
-	0601  VT8601
 	0505  VT82C505
 	0561  VT82C561
 	0571  VT82C586 IDE [Apollo]
@@ -1434,11 +1883,17 @@
 		1106 0000  MVP3 ISA Bridge
 	0595  VT82C595 [Apollo VP2]
 	0596  VT82C596 ISA [Apollo PRO]
+		1106 0000  VT82C596/A/B PCI to ISA Bridge
+		1458 0596  VT82C596/A/B PCI to ISA Bridge
 	0597  VT82C597 [Apollo VP3]
 	0598  VT82C598 [Apollo MVP3]
+	0601  VT8601
 	0680  VT82C680 [Apollo P6]
 	0686  VT82C686 [Apollo Super]
+		1106 0000  VT82C686/A PCI to ISA Bridge
+		1106 0686  VT82C686/A PCI to ISA Bridge
 	0691  VT82C691 [Apollo PRO]
+		1458 0691  VT82C691 Apollo Pro System Controller
 	0693  VT82C693 [Apollo Pro Plus]
 	0926  VT82C926 [Amazon]
 	1000  VT82C570MV
@@ -1449,10 +1904,13 @@
 		1234 0925  MVP3 USB Controller
 	3040  VT82C586B ACPI
 	3043  VT86C100A [Rhine 10/100]
-		1106 0100  VT86C100A
+		10bd 0000  VT86C100A Fast Ethernet Adapter
+		1106 0100  VT86C100A Fast Ethernet Adapter
 		1186 1400  DFE-530TX
+	3044  OHCI Compliant IEEE 1394 Host Controller
 	3057  VT82C686 [Apollo Super ACPI]
 	3058  VT82C686 [Apollo Super AC97/Audio]
+		1462 3091  MS-6309 Onboard Audio
 	3068  VT82C686 [Apollo Super AC97/Modem]
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
@@ -1462,8 +1920,8 @@
 	8596  VT82C596 [Apollo PRO AGP]
 	8597  VT82C597 [Apollo VP3 AGP]
 	8598  VT82C598 [Apollo MVP3 AGP]
-	8691  VT82C691 [Apollo Pro]
 	8601  VT8601
+	8691  VT82C691 [Apollo Pro]
 1107  Stratus Computers
 	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
 1108  Proteon, Inc.
@@ -1473,8 +1931,8 @@
 	0108  P1690Plus
 	0138  P1690Plus
 	0139  P1690Plus
-	013C  P1690Plus
-	013D  P1690Plus
+	013c  P1690Plus
+	013d  P1690Plus
 1109  Cogent Data Technologies, Inc.
 	1400  EM110TX [EX110TX]
 110a  Siemens Nixdorf AG
@@ -1495,23 +1953,27 @@
 # DJ- Some people say that 0x1112 is Rockwell International ?
 1112  RNS - Div. of Meret Communications Inc
 	2200  FDDI Adapter
+	2300  Fast Ethernet Adapter
 	2340  4 Port Fast Ethernet Adapter
 	2400  ATM Adapter
 1113  Accton Technology Corporation
 	1211  SMC2-1211TX
+		103c 1207  EN-1207D Fast Ethernet Adapter
+		1113 1211  EN-1207D Fast Ethernet Adapter
 	1217  EN-1217 Ethernet Adapter
 	5105  10Mbps Network card
 	9211  EN-1207D Fast Ethernet Adapter
+		1113 9211  EN-1207D Fast Ethernet Adapter
 1114  Atmel Corporation
 1115  3D Labs
 1116  Data Translation
 	0022  DT3001
 	0023  DT3002
 	0024  DT3003
-	0028  DT3003-PGL
 	0025  DT3004
 	0026  DT3005
 	0027  DT3001-PGL
+	0028  DT3003-PGL
 1117  Datacube, Inc
 	9500  Max-1C SVGA card
 	9501  Max-1C image processing
@@ -1545,8 +2007,8 @@
 	0115  GDT 6121RP1/6521RP1
 	0118  GDT 6x18RD
 	0119  GDT 6x28RD
-	011A  GDT 6x38RD
-	011B  GDT 6x58RD
+	011a  GDT 6x38RD
+	011b  GDT 6x58RD
 	0120  GDT 6117RP2/6517RP2
 	0121  GDT 6127RP2/6527RP2
 	0122  GDT 6537RP2
@@ -1555,8 +2017,8 @@
 	0125  GDT 6121RP2/6521RP2
 	0168  GDT 7x18RN
 	0169  GDT 7x28RN
-	016A  GDT 7x38RN
-	016B  GDT 7x58RN
+	016a  GDT 7x38RN
+	016b  GDT 7x58RN
 	0210  GDT 6x19RD
 	0211  GDT 6x29RD
 	0260  GDT 7x19RN
@@ -1565,7 +2027,9 @@
 	0000  155P-MF1 (FPGA)
 	0002  155P-MF1 (ASIC)
 	0003  ENI-25P ATM Adapter
+		111a 0000  ENI-25p Miniport ATM Adapter
 	0005  Speedstream 30xx ATM Adapter
+		111a 0001  SS-3010 Miniport ATM Adapter
 111b  Teledyne Electronic Systems
 111c  Tricord Systems Inc.
 	0001  Powerbis Bridge
@@ -1581,6 +2045,7 @@
 1123  Excellent Design, Inc.
 1124  Leutron Vision AG
 1125  Eurocore
+1126  Vigra
 1127  FORE Systems Inc
 	0200  ForeRunner PCA-200 ATM
 	0210  PCA-200PC
@@ -1601,6 +2066,9 @@
 1131  Philips Semiconductors
 	7145  SAA7145
 	7146  SAA7146
+		114b 2003  DVRaptor Video Edit/Capture Card
+		11bd 0006  DV500 Overlay
+		11bd 000a  DV500 Overlay
 1132  Mitel Corp.
 1133  Eicon Technology Corporation
 	7901  EiconCard S90
@@ -1612,11 +2080,17 @@
 	b921  EiconCard P92
 	b922  EiconCard P92
 	e001  DIVA 20PRO
+		1133 e001  DIVA Pro 2.0 S/T
 	e002  DIVA 20
+		1133 e002  DIVA 2.0 S/T
 	e003  DIVA 20PRO_U
+		1133 e003  DIVA Pro 2.0 U
 	e004  DIVA 20_U
+		1133 e004  DIVA 2.0 U
 	e010  DIVA Server BRI-2M
+		1133 e010  DIVA Server BRI-2M
 	e014  DIVA Server PRO-30M
+		1133 e014  DIVA Server PRI-30M
 1134  Mercury Computer Systems
 	0001  Raceway Bridge
 1135  Fuji Xerox Co Ltd
@@ -1626,6 +2100,7 @@
 1138  Ziatech Corporation
 	8905  8905 [STD 32 Bridge]
 1139  Dynamic Pictures, Inc
+	0001  VGA Compatable 3D Graphics
 113a  FWB Inc
 113b  Network Computing Devices
 113c  Cyclone Microsystems, Inc.
@@ -1640,9 +2115,9 @@
 113f  Equinox Systems, Inc.
 	0808  SST-64P Adapter
 	1010  SST-128P Adapter
-	80C0  SST-16P Adapter
-	80C4  SST-16P Adapter
-	80C8  SST-16P Adapter
+	80c0  SST-16P Adapter
+	80c4  SST-16P Adapter
+	80c8  SST-16P Adapter
 	8888  SST-4P Adapter
 	9090  SST-8P Adapter
 1140  Intervoice Inc
@@ -1699,8 +2174,8 @@
 	0006  AccelePort Xr,C/X
 	0009  AccelePort Xr/J
 	000a  AccelePort EPC/J
-	000C  DataFirePRIme T1 (1-port)
-	000D  SyncPort 2-Port (x.25/FR)
+	000c  DataFirePRIme T1 (1-port)
+	000d  SyncPort 2-Port (x.25/FR)
 	0011  AccelePort 8r EIA-232 (IBM)
 	0012  AccelePort 8r EIA-422
 	0013  AccelePort Xr
@@ -1708,9 +2183,9 @@
 	0015  AccelePort Xem
 	0016  AccelePort EPC/X
 	0017  AccelePort C/X
-	001A  DataFirePRIme E1 (1-port)
-	001B  AccelePort C/X (IBM)
-	001D  DataFire RAS T1/E1/PRI
+	001a  DataFirePRIme E1 (1-port)
+	001b  AccelePort C/X (IBM)
+	001d  DataFire RAS T1/E1/PRI
 	0023  AccelePort RAS
 	0024  DataFire RAS B4 ST/U
 	0026  AccelePort 4r 920
@@ -1760,6 +2235,7 @@
 		1014 0183  10/100 EtherJet Cardbus Adapter
 		115d 0183  Cardbus Ethernet 10/100
 	0101  Cardbus 56k modem
+		115d 1081  Cardbus 56k Modem
 	0103  Cardbus Ethernet + 56k Modem
 		115d 1181  CBEM56G-100 Ethernet + 56k Modem
 		8086 9181  PRO/100 LAN + Modem56 CardBus
@@ -1771,10 +2247,12 @@
 1163  Rendition
 	0001  Verite 1000
 	2000  Verite V2000/V2100/V2200
+		1092 2000  Stealth II S220
 1164  Advanced Peripherals Technologies
 1165  Imagraph Corporation
 	0001  Motion TPEG Recorder/Player with audio
 1166  Relience Computer
+	0007  CNB20-LE CPU to PCI Bridge
 	0008  CNB20HE
 	0009  CNB20HE
 1167  Mutoh Industries Inc
@@ -1799,6 +2277,7 @@
 1176  SBE Incorporated
 1177  Silicon Engineering
 1178  Alfa, Inc.
+	afa1  Fast Ethernet Adapter
 1179  Toshiba America Info Systems
 	0404  DVD Decoder card
 	0406  Tecra Video Capture device
@@ -1807,9 +2286,14 @@
 	0603  ToPIC95 PCI to CardBus Bridge for Notebooks
 	060a  ToPIC95
 	060f  ToPIC97
+	0617  ToPIC95 PCI to Cardbus Bridge with ZV Support
+	0618  CPU to PCI and PCI to ISA bridge
 	0701  FIR Port
 # This is apparently incorrect. Does anyone know the correct ID?
 #	0701  Lucent DSP1645 [Mars]
+	0d01  FIR Port Type-DO
+		1179 0001  FIR Port Type-DO
+117a  A-Trend Technology
 117b  L G Electronics, Inc.
 117c  Atto Technology
 117d  Becton & Dickinson
@@ -1856,9 +2340,13 @@
 118e  Hermstedt GmbH
 118f  Green Logic
 1190  Tripace
+	c731  TP-910/920/940 PCI Ultra(Wide) SCSI Adapter
 1191  Artop Electronic Corp
+	0003  SCSI Cache Host Adapter
 	0004  ATP8400
 	0005  ATP850UF
+	0006  ATP860 NO-BIOS
+	0007  ATP860
 	8002  AEC6710 SCSI-2 Host Adapter
 	8010  AEC6712UW SCSI
 	8020  AEC6712U SCSI
@@ -1906,6 +2394,7 @@
 		11ad f003  LNE100TX
 		11ad ffff  LNE100TX
 		1385 f004  FA310TX
+	c115  LNE100TX Fast Ethernet Adapter
 11ae  Aztech System Ltd
 11af  Avid Technology Inc.
 11b0  V3 Semiconductor Inc.
@@ -1918,6 +2407,7 @@
 11b4  Leitch Technology International
 11b5  Radstone Technology Plc
 11b6  United Video Corp
+11b7  Motorola
 11b8  XPoint Technologies, Inc
 	0001  Quad PeerMaster
 11b9  Pathlight Technology Inc.
@@ -1974,6 +2464,11 @@
 		144d 2104  LT56PT Modem
 		149f 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		1668 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+	0443  LT WinModem
+	0444  LT WinModem
+	0445  LT WinModem
+	0446  LT WinModem
+	0447  LT WinModem
 	0448  WinModem 56k
 		13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd
 	0449  WinModem 56k
@@ -1982,12 +2477,28 @@
 		13e0 0041  TelePath Internet 56k WinModem
 		144f 0449  Lucent 56k V.90 DFi Modem
 		1468 0449  Presario 56k V.90 DFi Modem
-	044A  F-1156IV WinModem (V90, 56KFlex)
+	044a  F-1156IV WinModem (V90, 56KFlex)
 		13e0 0012  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		13e0 0042  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		144f 1005  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+	044b  LT WinModem
+	044c  LT WinModem
+	044d  LT WinModem
+	044e  LT WinModem
+	0450  LT WinModem
+	0451  LT WinModem
+	0452  LT WinModem
+	0453  LT WinModem
+	0454  LT WinModem
+	0455  LT WinModem
+	0456  LT WinModem
+	0457  LT WinModem
+	0458  LT WinModem
+	0459  LT WinModem
+	045a  LT WinModem
 	0480  Venus WinModem (V90, 56KFlex)
 11c2  Sand Microelectronics
+11c3  NEC Corp
 11c4  Document Technologies, Inc
 11c5  Shiva Corporation
 11c6  Dainippon Screen Mfg. Co. Ltd
@@ -2070,6 +2581,7 @@
 	1401  ReadyLink 2000
 	2011  RL100-ATX 10/100
 	2201  ReadyLink 100TX (Winbond W89C840)
+		11f6 2011  ReadyLink 100TX
 	9881  RL100TX
 11f7  Scientific Atlanta
 11f8  PMC-Sierra Inc.
@@ -2088,9 +2600,9 @@
 	0006  RocketPort 8J
 	0008  RocketPort 8-port
 	0009  RocketPort 16-port
-	000A  RocketPort Plus Quadcable
-	000B  RocketPort Plus Octacable
-	000C  RocketPort 8-port Modem
+	000a  RocketPort Plus Quadcable
+	000b  RocketPort Plus Octacable
+	000c  RocketPort 8-port Modem
 11ff  Scion Corporation
 1200  CSS Corporation
 1201  Vista Controls Corp
@@ -2129,6 +2641,8 @@
 	673a  6730
 	6832  6832
 	6836  6836
+	6872  OZ6812 Cardbus Controller
+	6933  OZ6933 Cardbus Controller
 1218  Hybricon Corp.
 1219  First Virtual Corporation
 121a  3Dfx Interactive, Inc.
@@ -2142,10 +2656,16 @@
 		1092 4803  Monster Fusion AGP
 		1092 8030  Monster Fusion
 		1092 8035  Monster Fusion AGP
+		10b0 0001  Dragon 4000
+		1102 1017  CT6760 3D Blaster Banshee
 		121a 0001  Voodoo Banshee AGP
 		121a 0003  Voodoo Banshee AGP SGRAM
 		121a 0004  Voodoo Banshee
+		139c 0016  Raven
+		139c 0017  Raven
+		14af 0002  Maxi Gamer Phoenix
 		3030 3030  Skywell Magic TwinPower
+	0004  Voodoo Banshee
 	0005  Voodoo 3
 		121a 0004  Voodoo3 AGP
 		121a 0030  Voodoo3 AGP
@@ -2186,7 +2706,9 @@
 122d  Aztech System Ltd
 	1206  368DSP
 	50dc  3328 Audio
+		122d 0001  3328 Audio
 	80da  3328 Audio
+		122d 0001  3328 Audio
 122e  Xyratex
 122f  Andrew Corporation
 1230  Fishcamp Engineering
@@ -2211,7 +2733,13 @@
 123e  Simutech, Inc.
 123f  C-Cube Microsystems
 	00e4  MPEG
+	8120  E4?
+		11bd 0006  DV500 E4
+		11bd 000a  DV500 E4
 	8888  Cinemaster C 3.0 DVD Decoder
+		1002 0001  Cinemaster C 3.0 DVD Decoder
+		1002 0002  Cinemaster C 3.0 DVD Decoder
+		1328 0001  Cinemaster C 3.0 DVD Decoder
 1240  Marathon Technologies Corp.
 1241  DSC Communications
 1242  Jaycor Networks, Inc.
@@ -2220,6 +2748,7 @@
 1244  AVM Audiovisuelles MKTG & Computer System GmbH
 	0700  B1 ISDN
 	0a00  A1 ISDN [Fritz]
+		1244 0a00  FRITZ!Card ISDN Controller
 1245  A.P.D., S.A.
 1246  Dipix Technologies, Inc.
 1247  Xylon Research, Inc.
@@ -2257,10 +2786,26 @@
 	0000  ES336H Fax Modem (Early Model)
 	1948  Solo?
 	1968  ES1968 Maestro 2
+		1028 0085  ES1968 Maestro-2 PCI
+		1033 8051  ES1968 Maestro-2 Audiodrive
 	1969  ES1969 Solo-1 Audiodrive
+		1014 0166  ES1969 SOLO-1 AudioDrive on IBM Aptiva Mainboard
+		125d 8888  Solo-1 Audio Adapter
+		525f c888  ES1969 SOLO-1 AudioDrive (+ES1938)
 	1978  ES1978 Maestro 2E
+		1033 803c  ES1978 Maestro-2E Audiodrive
+		1033 8058  ES1978 Maestro-2E Audiodrive
+		1092 4000  Monster Sound MX400
+		1179 0001  ES1978 Maestro-2E Audiodrive
 	1988  ES1988 Allegro-1
+		1092 4100  Sonic Impact S100
+		125d 1988  ESS Allegro-1 Audiodrive
+	1989  ESS Modem
+		125d 1989  ESS Modem
+	1998  ES1983S Maestro-3i PCI Audio Accelerator
+	1999  ES1983S Maestro-3i PCI Modem Accelerator
 	2808  ES336H Fax Modem (Later Model)
+	2838  ES2838/2839 SuperLink Modem
 	2898  ES2898 Modem
 125e  Specialvideo Engineering SRL
 125f  Concurrent Technologies, Inc.
@@ -2275,6 +2820,7 @@
 1266  Microdyne Corporation
 	0001  NE10/100 Adapter (i82557B)
 	1910  NE2000Plus (RT8029) Ethernet Adapter
+		1266 1910  NE2000Plus Ethernet Adapter
 1267  S. A. Telecommunications
 	5352  PCR2101
 	5a4b  Telsat Turbo
@@ -2286,6 +2832,12 @@
 126d  Splash Technology, Inc.
 126e  Sumitomo Metal Industries, Ltd.
 126f  Silicon Motion, Inc.
+	0710  SM710 LynxEM
+	0712  SM712 LynxEM+
+	0720  SM720 Lynx3DM
+	0810  SM810 LynxE
+	0811  SM811 LynxE
+	0820  SM820 Lynx3D
 	0910  SM910
 1270  Olympus Optical Co., Ltd.
 1271  GW Instruments
@@ -2294,7 +2846,66 @@
 	0002  DirecPC
 1274  Ensoniq
 	1371  ES1371 [AudioPCI-97]
+		0e11 b1a7  ES1371, ES1373 AudioPCI
+		1033 80ac  ES1371, ES1373 AudioPCI
+		1042 1854  Tazer
+		107b 8054  Tabor2
+		1274 1371  Creative Sound Blaster AudioPCI64V, AudioPCI128
+		1462 6470  ES1371, ES1373 AudioPCI On Motherboard MS-6147 1.1A
+		1462 6560  ES1371, ES1373 AudioPCI On Motherboard MS-6156 1.10
+		1462 6630  ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 1.0A
+		1462 6631  ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 1.0A
+		1462 6632  ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 2.0A
+		1462 6633  ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 2.0A
+		1462 6820  ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00
+		1462 6822  ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00A
+		1462 6830  ES1371, ES1373 AudioPCI On Motherboard MS-6183 1.00
+		1462 6880  ES1371, ES1373 AudioPCI On Motherboard MS-6188 1.00
+		1462 6900  ES1371, ES1373 AudioPCI On Motherboard MS-6190 1.00
+		1462 6910  ES1371, ES1373 AudioPCI On Motherboard MS-6191
+		1462 6930  ES1371, ES1373 AudioPCI On Motherboard MS-6193
+		1462 6990  ES1371, ES1373 AudioPCI On Motherboard MS-6199BX 2.0A
+		1462 6991  ES1371, ES1373 AudioPCI On Motherboard MS-6199VIA 2.0A
+		14a4 2077  ES1371, ES1373 AudioPCI On Motherboard KR639
+		14a4 2105  ES1371, ES1373 AudioPCI On Motherboard MR800
+		14a4 2107  ES1371, ES1373 AudioPCI On Motherboard MR801
+		14a4 2172  ES1371, ES1373 AudioPCI On Motherboard DR739
+		1509 9902  ES1371, ES1373 AudioPCI On Motherboard KW11
+		1509 9903  ES1371, ES1373 AudioPCI On Motherboard KW31
+		1509 9904  ES1371, ES1373 AudioPCI On Motherboard KA11
+		1509 9905  ES1371, ES1373 AudioPCI On Motherboard KC13
+		152d 8801  ES1371, ES1373 AudioPCI On Motherboard CP810E
+		152d 8802  ES1371, ES1373 AudioPCI On Motherboard CP810
+		152d 8803  ES1371, ES1373 AudioPCI On Motherboard P3810E
+		152d 8804  ES1371, ES1373 AudioPCI On Motherboard P3810-S
+		152d 8805  ES1371, ES1373 AudioPCI On Motherboard P3820-S
+		270f 2001  ES1371, ES1373 AudioPCI On Motherboard 6CTR
+		270f 2200  ES1371, ES1373 AudioPCI On Motherboard 6WTX
+		270f 3000  ES1371, ES1373 AudioPCI On Motherboard 6WSV
+		270f 3100  ES1371, ES1373 AudioPCI On Motherboard 6WIV2
+		270f 3102  ES1371, ES1373 AudioPCI On Motherboard 6WIV
+		270f 7060  ES1371, ES1373 AudioPCI On Motherboard 6ASA2
+		8086 4249  ES1371, ES1373 AudioPCI On Motherboard BI440ZX
+		8086 424c  ES1371, ES1373 AudioPCI On Motherboard BL440ZX
+		8086 425a  ES1371, ES1373 AudioPCI On Motherboard BZ440ZX
+		8086 4341  ES1371, ES1373 AudioPCI On Motherboard Cayman
+		8086 4343  ES1371, ES1373 AudioPCI On Motherboard Cape Cod
+		8086 4649  ES1371, ES1373 AudioPCI On Motherboard Fire Island
+		8086 464a  ES1371, ES1373 AudioPCI On Motherboard FJ440ZX
+		8086 4d4f  ES1371, ES1373 AudioPCI On Motherboard Montreal
+		8086 4f43  ES1371, ES1373 AudioPCI On Motherboard OC440LX
+		8086 5243  ES1371, ES1373 AudioPCI On Motherboard RC440BX
+		8086 5352  ES1371, ES1373 AudioPCI On Motherboard SunRiver
+		8086 5643  ES1371, ES1373 AudioPCI On Motherboard Vancouver
+		8086 5753  ES1371, ES1373 AudioPCI On Motherboard WS440BX
 	5000  ES1370 [AudioPCI]
+	5880  5880 AudioPCI
+		1274 2000  Creative Sound Blaster AudioPCI128
+		1274 5880  Creative Sound Blaster AudioPCI128
+		1462 6880  5880 AudioPCI On Motherboard MS-6188 1.00
+		270f 2001  5880 AudioPCI On Motherboard 6CTR
+		270f 2200  5880 AudioPCI On Motherboard 6WTX
+		270f 7040  5880 AudioPCI On Motherboard 6ATA4
 1275  Network Appliance Corporation
 1276  Switched Network Technologies, Inc.
 1277  Comstream
@@ -2303,15 +2914,37 @@
 	0295  Virtual Northbridge
 127a  Rockwell International
 	1002  HCF 56k V90 FaxModem
+		127a 1002  HCF 56k V90 Modem
 	1003  HCF 56k V90 FaxModem
+		127a 1003  PCI56RX Modem
+		13df 1003  PCI56RX Modem
 	1004  HCF 56k V90 FaxModem
 	1005  HCF 56k V90 FaxModem
 		122d 4008  MDP3858SP-A SVD Modem
 		127a 1005  PCI56RVP Modem 
 		13df 1005  PCI56RVP Modem 
 		1436 1005  WS-5614PS3G
+	1025  HCF 56k PCI Modem
+		127a 1025  HCF 56k PCI Modem
+	1026  HCF 56k PCI Speakerphone Modem
+		127a 1026  HCF 56k PCI Speakerphone Modem
+	1035  HCF 56k PCI Speakerphone Modem
+		127a 1035  HCF 56k PCI Speakerphone Modem
+	1085  Volcano HCF 56k PCI Modem
+		127a 1085  Volcano HCF 56k PCI Modem
 	2005  HCF 56k V90 FaxModem
+		127a 2005  Conexant SoftK56 Speakerphone Modem
+	2015  Conexant SoftK56 Speakerphone Modem
+		127a 2015  Conexant SoftK56 Speakerphone Modem
+		14c8 2115  Conexant SoftK56 Speakerphone Modem
+	4320  Riptide PCI Audio Controller
+		1235 4320  Riptide PCI Audio Controller
+	4321  Riptide HCF 56k PCI Modem
+		1235 4321  Riptide HCF 56k PCI Modem
+	4322  Riptide PCI Game Controller
+		1235 4322  Riptide PCI Game Controller
 	8234  RapidFire 616X ATM155 Adapter
+		108d 0027  RapidFire 616X ATM155 Adapter
 127b  Pixera Corporation
 127c  Crosspoint Solutions, Inc.
 127d  Vela Research
@@ -2324,6 +2957,8 @@
 1283  Integrated Technology Express, Inc.
 	673a  IT8330G
 	8330  IT8330G
+	8888  IT8888F PCI to ISA Bridge with SMB
+	8889  IT8889F PCI to ISA Bridge
 	e886  IT8330G
 1284  Sahara Networks, Inc.
 1285  Platform Technologies, Inc.
@@ -2374,6 +3009,7 @@
 12a9  Xiotech Corporation
 12aa  SDL Communications, Inc.
 12ab  Yuan Yuan Enterprise Co., Ltd.
+	3000  MPG-200C PCI DVD Decoder Card
 12ac  Measurex Corporation
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
@@ -2390,7 +3026,23 @@
 12b8  Korg
 12b9  US Robotics/3Com
 	1006  WinModem
+		12b9 005c  USR 56k Internal Voice WinModem (Model 3472)
+		12b9 005e  USR 56k Internal WinModem (Models 662975)
+		12b9 0062  USR 56k Internal Voice WinModem (Model 662978)
+		12b9 0068  USR 56k Internal Voice WinModem (Model 5690)
+		12b9 007a  USR 56k Internal Voice WinModem (Model 662974)
+		12b9 007f  USR 56k Internal WinModem (Models 5698, 5699)
+		12b9 0080  USR 56k Internal WinModem (Models 2975, 3528)
+		12b9 0081  USR 56k Internal Voice WinModem (Models 2974, 3529)
+		12b9 0091  USR 56k Internal Voice WinModem (Model 2978)
+	1007  USR 56k Internal WinModem
+		12b9 00a3  USR 56k Internal WinModem (Model 3595)
 	1008  56K FaxModem Model 5610
+		12b9 00a2  USR 56k Internal FAX Modem (Model 2977)
+		12b9 00aa  USR 56k Internal Voice Modem (Model 2976)
+		12b9 00ab  USR 56k Internal Voice Modem (Model 5609)
+		12b9 00ac  USR 56k Internal Voice Modem (Model 3298)
+		12b9 00ad  USR 56k Internal FAX Modem (Model 5610)
 12ba  PMC Sierra
 12bb  Nippon Unisoft Corporation
 12bc  Array Microsystems
@@ -2398,6 +3050,7 @@
 12be  Anchor Chips Inc.
 	3041  AN3041Q CO-MEM
 	3042  AN3042Q CO-MEM Lite
+		12be 3042  Anchor Chips Lite Evaluation Board
 12bf  Fujifilm Microdevices
 12c0  Infimed
 12c1  GMM Research Corp
@@ -2436,12 +3089,13 @@
 		10b4 222a  STB Velocity 128 AGP
 		10b4 2230  STB Velocity 128
 		10b4 2235  STB Velocity 128 AGP
+		2a15 54a3  3DVision-SAGP
 	0019  Riva128ZX
 	0020  TNT
 	0028  TNT2
 	0029  UTNT2
-	002C  VTNT2
-	00A0  ITNT2
+	002c  VTNT2
+	00a0  ITNT2
 12d3  Vingmed Sound A/S
 12d4  DGM&S
 12d5  Equator Technologies
@@ -2471,7 +3125,38 @@
 12ea  Zuken
 12eb  Aureal Semiconductor
 	0001  Vortex 1
+		104d 8036  AU8820 Vortex Digital Audio Processor
+		1092 2000  Sonic Impact A3D
+		1092 2100  Sonic Impact A3D
+		1092 2110  Sonic Impact A3D
+		1092 2200  Sonic Impact A3D
+		12eb 0001  AU8820 Vortex Digital Audio Processor
+		5053 3355  Montego
 	0002  Vortex 2
+		104d 8049  AU8830 Vortex 3D Digital Audio Processor
+		104d 807b  AU8830 Vortex 3D Digital Audio Processor
+		1092 3000  Monster Sound II
+		1092 3001  Monster Sound II
+		1092 3002  Monster Sound II
+		1092 3003  Monster Sound II
+		1092 3004  Monster Sound II
+		12eb 0001  AU8830 Vortex 3D Digital Audio Processor
+		12eb 0002  AU8830 Vortex 3D Digital Audio Processor
+		12eb 0088  AU8830 Vortex 3D Digital Audio Processor
+		144d 3510  AU8830 Vortex 3D Digital Audio Processor
+		5053 3356  Montego II
+	0003  AU8810 Vortex Digital Audio Processor
+		104d 8049  AU8810 Vortex Digital Audio Processor
+		104d 8077  AU8810 Vortex Digital Audio Processor
+		109f 1000  AU8810 Vortex Digital Audio Processor
+		12eb 0003  AU8810 Vortex Digital Audio Processor
+		1462 6780  AU8810 Vortex Digital Audio Processor
+		14a4 2073  AU8810 Vortex Digital Audio Processor
+		14a4 2091  AU8810 Vortex Digital Audio Processor
+		14a4 2104  AU8810 Vortex Digital Audio Processor
+		14a4 2106  AU8810 Vortex Digital Audio Processor
+	8803  Vortex 56k Software Modem
+		12eb 8803  Vortex 56k Software Modem
 12ec  3A International, Inc.
 12ed  Optivision Inc.
 12ee  Orange Micro
@@ -2500,10 +3185,10 @@
 1306  Duet Technologies
 1307  Computer Boards
 	0001  PCI-DAS1602/16
-	000C  PCI-PDISO8
-	000D  PCI-PDISO16
-	000B  PCI-DIO48H
-	000F  PCI-DAS1200
+	000b  PCI-DIO48H
+	000c  PCI-PDISO8
+	000d  PCI-PDISO16
+	000f  PCI-DAS1200
 	0010  PCI-DAS1602/12
 	0014  PCI-DIO24H
 	0015  PCI-DIO24H/CTR3
@@ -2511,12 +3196,12 @@
 	0017  PCI-DIO96H
 	0018  PCI-CTR05
 	0019  PCI-DAS1200/JR
-	001A  PCI-DAS1001
-	001B  PCI-DAS1002
-	001C  PCI-DAS1602JR/16
-	001D  PCI-DAS6402/16
-	001E  PCI-DAS6402/12
-	001F  PCI-DAS16/M1
+	001a  PCI-DAS1001
+	001b  PCI-DAS1002
+	001c  PCI-DAS1602JR/16
+	001d  PCI-DAS6402/16
+	001e  PCI-DAS6402/12
+	001f  PCI-DAS16/M1
 	0020  PCI-DDA02/12
 	0021  PCI-DDA04/12
 	0022  PCI-DDA08/12
@@ -2527,15 +3212,16 @@
 	0027  PCI-DAC04/16-HS
 	0028  PCI-DIO24
 	0029  PCI-DAS08
-	002C  PCI-INT32
+	002c  PCI-INT32
 	0033  PCI-DUAL-AC5
 	0034  PCI-DAS-TC
 	0035  PCI-DAS64/M1/16
 	0036  PCI-DAS64/M2/16
 	0037  PCI-DAS64/M3/16
-	004C  PCI-DAS1000
+	004c  PCI-DAS1000
 1308  Jato Technologies Inc.
 	0001  NetCelerator Adapter
+		1308 0001  NetCelerator Adapter
 1309  AB Semiconductor Ltd
 130a  Mitsubishi Electric Microcomputer
 130b  Colorgraphic Communications Corp
@@ -2550,9 +3236,12 @@
 1316  Teradyne Inc
 1317  Bridgecom, Inc
 1318  Packet Engines Inc.
+	0911  PCI Ethernet Adapter
 1319  Fortemedia, Inc
 	0801  Xwave QS3000A [FM801]
 	0802  Xwave QS3000A [FM801 game port]
+	1000  FM801 PCI Audio
+	1001  FM801 PCI Joystick
 131a  Finisar Corp.
 131c  Nippon Electro-Sensory Devices Corp
 131d  Sysmic, Inc.
@@ -2584,6 +3273,7 @@
 	2020  CyberParallel (1-port)
 	2021  CyberParallel (2-port)
 	2030  CyberSerial (2-port) 16550
+		131f 2030  PCI Serial Card
 	2031  CyberSerial (2-port) 16650
 	2032  CyberSerial (2-port) 16850
 	2040  Trio 1S(16550)+2P
@@ -2632,9 +3322,19 @@
 1349  Sumitomo Electric Industries, Ltd.
 134a  DTC Technology Corp.
 	0001  Domex 536
+	0002  Domex DMX3194UP SCSI Adapter
 134b  ARK Research Corp.
 134c  Chori Joho System Co. Ltd
 134d  PCTel Inc
+	7890  HSP MicroModem 56
+	7891  HSP MicroModem 56
+		134d 0001  HSP MicroModem 56
+	7892  HSP MicroModem 56
+	7893  HSP MicroModem 56
+	7894  HSP MicroModem 56
+	7895  HSP MicroModem 56
+	7896  HSP MicroModem 56
+	7897  HSP MicroModem 56
 134e  CSTI
 134f  Algo System Co Ltd
 1350  Systec Co. Ltd
@@ -2656,6 +3356,7 @@
 	7402  Four Port RS-422/485 Interface
 	7801  Eight Port RS-232 Interface
 	8001  8001 Digital I/O Adapter
+135f  I-Data International A-S
 1360  Meinberg Funkuhren
 1361  Soliton Systems K.K.
 1362  Fujifacom Corporation
@@ -2713,8 +3414,8 @@
 1396  Cipher Systems Inc
 1397  Cologne Chip Designs GmbH
 	2bd0  ISDN network controller [HFC-PCI]
-		1397 2bd0 ISDN Board
-		e4bf 1000 CI1-1-Harp
+		1397 2bd0  ISDN Board
+		e4bf 1000  CI1-1-Harp
 1398  Clarion co. Ltd
 1399  Rios systems Co Ltd
 139a  Alacritech Inc
@@ -2790,6 +3491,7 @@
 13de  ABB Robotics Products AB
 13df  E-Tech Inc
 	0001  PCI56RVP Modem
+		13df 0001  PCI56RVP Modem 
 13e0  GVC Corporation
 13e1  Silicom Multimedia Systems Inc
 13e2  Dynamics Research Corporation
@@ -2814,8 +3516,11 @@
 13f5  Kansai Electric Co. Ltd
 13f6  C-Media Electronics Inc
 	0100  CM8338A
+		13f6 ffff  CMI8338/C3DX PCI Audio Device
 	0101  CM8338B
+		13f6 0101  CMI8338-031 PCI Audio Device
 	0111  CM8738
+		13f6 0111  CMI8738/C3DX PCI Audio Device
 	0211  CM8738
 13f7  Wildfire Communications
 13f8  Ad Lib Multimedia Inc
@@ -2904,6 +3609,16 @@
 1448  Alesis Studio Electronics
 1449  TUT Systems Inc
 144a  Adlink Technology
+	7296  PCI-7296
+	7432  PCI-7432
+	7433  PCI-7433
+	7434  PCI-7434
+	7841  PCI-7841
+	8133  PCI-8133
+	8554  PCI-8554
+	9111  PCI-9111
+	9113  PCI-9113
+	9114  PCI-9114
 144b  Loronix Information Systems Inc
 144c  Catalina Research Inc
 144d  Samsung Electronics Co Ltd
@@ -2986,7 +3701,7 @@
 149a  ANDOR Technology Ltd
 149b  SEIKO Instruments Inc
 149c  OVISLINK Corp.
-149D  NEWTEK Inc
+149d  NEWTEK Inc
 149e  Mapletree Networks Inc.
 149f  LECTRON Co Ltd
 14a0  SOFTING GmBH
@@ -3084,7 +3799,27 @@
 14ef  CARRY Computer ENG. CO Ltd
 14f0  CANON RESEACH CENTRE FRANCE
 14f1  CONEXANT
+	1033  56K Winmodem
+		13e0 02b0  56K Winmodem
+	1035  PCI Modem Enumerator
+	2003  SoftK56 Winmodem
+		14f1 2003  SoftK56 Winmodem
+	2004  SoftK56 RemoteTAM Winmodem
+		14f1 2004  SoftK56 RemoteTAM Winmodem
+	2005  SoftK56 Speakerphone Winmodem
+		14f1 2005  SoftK56 Speakerphone Winmodem
+	2006  SoftK56 Speakerphone Winmodem
+		14f1 2006  SoftK56 Speakerphone Winmodem
 	2013  HSP MicroModem 56K
+		14f1 2013  SoftK56 Winmodem
+	2014  SoftK56 RemoteTAM Winmodem
+		144f 101c  SoftK56 RemoteTAM Winmodem
+		144f 2014  SoftK56 RemoteTAM Winmodem
+	2015  SoftK56 Speakerphone Winmodem
+		14c8 2115  SoftK56 Speakerphone Winmodem
+		14f1 2015  SoftK56 Speakerphone Winmodem
+	2016  SoftK56 Speakerphone Winmodem
+		14f1 2016  SoftK56 Speakerphone Winmodem
 14f2  MOBILITY Electronics
 14f3  BROADLOGIC
 14f4  TOKYO Electronic Industry CO Ltd
@@ -3109,6 +3844,16 @@
 # 1507  HTEC Ltd
 # Commented out because there are no known HTEC chips and 1507 is already
 # used by mistake by Motorola (see vendor ID 1057)
+1507  Motorola ?? / HTEC
+	0001  MPC105 [Eagle]
+	0002  MPC106 [Grackle]
+	0003  MPC8240 [Kahlua]
+	0100  MC145575 [HFC-PCI]
+	0431  KTI829c 100VG
+	4801  Raven
+	4802  Falcon
+	4803  Hawk
+	4806  CPX8216
 1508  HONDA CONNECTORS/MHOTRONICS Inc
 1509  FIRST INTERNATIONAL Computer Inc
 150a  FORVUS RESEARCH Inc
@@ -3195,7 +3940,189 @@
 1559  SI LOGIC Ltd
 155a  INNOMEDIA Inc
 155b  PROTAC INTERNATIONAL Corp
+155c  Cemax-Icon Inc
+155d  Mac System Co Ltd
+155e  LP Elektronik GmbH
+155f  Perle Systems Ltd
+1560  Terayon Communications Systems
+1561  Viewgraphics Inc
+1562  Symbol Technologies
+1563  A-Trend Technology Co Ltd
+1564  Yamakatsu Electronics Industry Co Ltd
+1565  Biostar Microtech Int'l Corp
+1566  Ardent Technologies Inc
+1567  Jungsoft
+1568  DDK Electronics Inc
+1569  Palit Microsystems Inc.
+156a  Avtec Systems
+156b  2wire Inc
+156c  Vidac Electronics GmbH
+156d  Alpha-Top Corp
+156e  Alfa Inc
+156f  M-Systems Flash Disk Pioneers Ltd
+1570  Lecroy Corp
+1571  Contemporary Controls
+1572  Otis Elevator Company
+1573  Lattice - Vantis
+1574  Fairchild Semiconductor
+1575  Voltaire Advanced Data Security Ltd
+1576  Viewcast COM
+1578  HITT
+1579  Dual Technology Corp
+157a  Japan Elecronics Ind Inc
+157b  Star Multimedia Corp
+157c  Eurosoft (UK)
+	8001  Fix2000 PCI Y2K Compliance Card
+157d  Gemflex Networks
+157e  Transition Networks
+157f  PX Instruments Technology Ltd
+1580  Primex Aerospace Co
+1581  SEH Computertechnik GmbH
+1582  Cytec Corp
+1583  Inet Technologies Inc
+1584  Uniwill Computer Corp
+1585  Logitron
+1586  Lancast Inc
+1587  Konica Corp
+1588  Solidum Systems Corp
+1589  Atlantek Microsystems Pty Ltd
+158a  Digalog Systems Inc
+158b  Allied Data Technologies
+158c  Hitachi Semiconductor & Devices Sales Co Ltd
+158d  Point Multimedia Systems
+158e  Lara Technology Inc
+158f  Ditect Coop
+1590  3pardata Inc
+1591  ARN
+1592  Syba Tech Ltd
+	0781  Multi-IO Card
+	0782  Parallel Port Card 2xEPP
+	0783  Multi-IO Card
+	0785  Multi-IO Card
+	0786  Multi-IO Card
+	0787  Multi-IO Card
+	0788  Multi-IO Card
+	078a  Multi-IO Card
+1593  Bops Inc
+1594  Netgame Ltd
+1595  Diva Systems Corp
+1596  Folsom Research Inc
+1597  Memec Design Services
+1598  Granite Microsystems
+1599  Delta Electronics Inc
+159a  General Instrument
+159b  Faraday Technology Corp
+159c  Stratus Computer Systems
+159d  Ningbo Harrison Electronics Co Ltd
+159e  A-Max Technology Co Ltd
+159f  Galea Network Security
+15a0  Compumaster SRL
+15a1  Geocast Network Systems
+15a2  Catalyst Enterprises Inc
+15a3  Italtel
+15a4  X-Net OY
+15a5  Toyota Macs Inc
+15a6  Sunlight Ultrasound Technologies Ltd
+15a7  SSE Telecom Inc
+15a8  Shanghai Communications Technologies Center
+15aa  Moreton Bay
+15ab  Bluesteel Networks Inc
+15ac  North Atlantic Instruments
+15ad  VMWare Inc
+	0710  Virtual SVGA
+15ae  Amersham Pharmacia Biotech
+15b0  Zoltrix International Ltd
+15b1  Source Technology Inc
+15b2  Mosaid Technologies Inc
+15b3  Mellanox Technology
+15b4  CCI/TRIAD
+15b5  Cimetrics Inc
+15b6  Texas Memory Systems Inc
+15b7  Sandisk Corp
+15b8  ADDI-DATA GmbH
+15b9  Maestro Digital Communications
+15ba  Impacct Technology Corp
+15bb  Portwell Inc
+15bc  Agilent Technologies
+15bd  DFI Inc
+15be  Sola Electronics
+15bf  High Tech Computer Corp (HTC)
+15c0  BVM Ltd
+15c1  Quantel
+15c2  Newer Technology Inc
+15c3  Taiwan Mycomp Co Ltd
+15c4  EVSX Inc
+15c5  Procomp Informatics Ltd
+15c6  Technical University of Budapest
+15c7  Tateyama Dystem Laboratory Co Ltd
+15c8  Penta Media Co Ltd
+15c9  Serome Technology Inc
+15ca  Bitboys OY
+15cb  AG Electronics Ltd
+15cc  Hotrail Inc
+15cd  Dreamtech Co Ltd
+15ce  Genrad Inc
+15cf  Hilscher GmbH
+15d1  Infineon Technologies AG
+15d2  FIC (First International Computer Inc)
+15d3  NDS Technologies Israel Ltd
+15d4  Iwill Corp
+15d5  Tatung Co
+15d6  Entridia Corp
+15d7  Rockwell-Collins Inc
+15d8  Cybernetics Technology Co Ltd
+15d9  Super Micro Computer Inc
+15da  Cyberfirm Inc
+15db  Applied Computing Systems Inc
+15dc  Litronic Inc
+	0001  Argus 300 PCI Cryptography Module
+15dd  Sigmatel Inc
+15de  Malleable Technologies Inc
+15df  Infinilink Corp
+15e0  Cacheflow Inc
+15e1  Voice Technologies Group Inc
+15e2  Quicknet Technologies Inc
+15e3  Networth Technologies Inc
+15e4  VSN Systemen BV
+15e5  Valley technologies Inc
+15e6  Agere Inc
+15e7  Get Engineering Corp
+15e8  National Datacomm Corp
+15e9  Pacific Digital Corp
+15ea  Tokyo Denshi Sekei K.K.
+15eb  Drsearch GmbH
+15ec  Beckhoff GmbH
+15ed  Macrolink Inc
+15ee  In Win Development Inc
+15ef  Intelligent Paradigm Inc
+15f0  B-Tree Systems Inc
+15f1  Times N Systems Inc
+15f2  Diagnostic Instruments Inc
+15f3  Digitmedia Corp
+15f4  Valuesoft
+15f5  Power Micro Research
+15f6  Extreme Packet Device Inc
+15f7  Banctec
+15f8  Koga Electronics Co
+15f9  Zenith Electronics Corp
+15fa  J.P. Axzam Corp
+15fb  Zilog Inc
+15fc  Techsan Electronics Co Ltd
+15fd  N-CUBED.NET
+15fe  Kinpo Electronics Inc
+15ff  Fastpoint Technologies Inc
+1600  Northrop Grumman - Canada Ltd
+1601  Tenta Technology
+1602  Prosys-tec Inc
+1603  Nokia Wireless Communications
+1604  Central System Research Co Ltd
+1605  Pairgain Technologies
+1606  Europop AG
+1607  Lava Semiconductor Manufacturing Inc
+1608  Automated Wagering International
+1609  Scimetric Instruments Inc
 1668  Action Tec Electronics Inc
+1813  Ambient Technologies Inc
 1a08  Sierra semiconductor
 	0000  SC15064
 1b13  Jaton Corp
@@ -3216,13 +4143,19 @@
 270b  Xantel Corporation
 270f  Chaintech Computer Co. Ltd
 2711  AVID Technology Inc.
+2a15  3D Vision(???)
 3000  Hansol Electronics Inc.
 3142  Post Impression Systems.
 3388  Hint Corp
 	8011  VXPro II Chipset
+		3388 8011  VXPro II Chipset CPU to PCI Bridge
 	8012  VXPro II Chipset
+		3388 8012  VXPro II Chipset PCI to ISA Bridge
 	8013  VXPro II Chipset
+		3388 8013  VXPro II Chipset EIDE Controller
+3411  Quantum Designs (H.K.) Inc
 3513  ARCOM Control Systems Ltd
+38ef  4Links
 3d3d  3DLabs
 	0001  GLINT 300SX
 	0002  GLINT 500TX
@@ -3247,6 +4180,9 @@
 	3d04  Permedia
 	ffff  Glint VGA
 4005  Avance Logic Inc.
+	0300  ALS300 PCI Audio Device
+	0308  ALS300+ PCI Audio Device
+	0309  PCI Input Controller
 	1064  ALG-2064
 	2064  ALG-2064i
 	2128  ALG-2364A GUI Accelerator
@@ -3256,7 +4192,11 @@
 	2364  ALG-2364A
 	2464  ALG-2464
 	2501  ALG-2564A/25128A
+	4000  ALS4000 Audio Chipset
+		4005 4000  ALS4000 Audio Chipset
 4033  Addtron Technology Co, Inc.
+4143  Digital Equipment Corp
+416c  Aladdin Knowledge Systems
 4444  Internext Compression Inc
 4468  Bridgeport machines
 4594  Cogetec Informatique Inc
@@ -3267,10 +4207,13 @@
 4978  Axil Computer Inc
 4a14  NetVin
 	5000  NV5000SC
+		4a14 5000  RT8029-Based Ethernet Adapter
 4b10  Buslogic Inc.
 4c48  LUNG HWA Electronics
+4ca1  Seanix Technology Inc
 4d51  MediaQ Inc.
 	0200  MQ-200
+4d54  Microtechnica Co Ltd
 4ddc  ILC Data Device Corp
 5053  Voyetra Technologies
 	2010  Daytona Audio Adapter
@@ -3314,7 +4257,9 @@
 	88f2  86c968 [Vision 968 VRAM] rev 2
 	88f3  86c968 [Vision 968 VRAM] rev 3
 	8900  86c755 [Trio 64V2/DX]
+		5333 8900  86C775 Trio64V2/DX
 	8901  Trio 64V2/DX or /GX
+		5333 8901  86C775 Trio64V2/DX, 86C785 Trio64V2/GX
 	8902  Plato/PX
 	8903  Trio 3D business multimedia
 	8904  Trio 64 3D
@@ -3341,7 +4286,9 @@
 	8a13  86c368 [Trio 3D/2X]
 		5333 8a13  Trio3D/2X
 	8a20  86c794 [Savage 3D]
+		5333 8a20  86C391 Savage3D
 	8a21  86c795 [Savage 3D/MV]
+		5333 8a21  86C390 Savage3D/MV
 	8a22  Savage 4
 		105d 0018  SR9 8Mb SDRAM
 		105d 002a  SR9 Pro 16Mb SDRAM
@@ -3349,20 +4296,42 @@
 		105d 092f  SR9 Pro+ 16Mb SGRAM
 		1092 4207  Stealth III S540
 		1092 4800  Stealth III S540
+		1092 4807  SpeedStar A90
 		1092 4808  Stealth III S540
+		1092 4809  Stealth III S540
 		1092 480e  Stealth III S540
 		1092 4904  Stealth III S520
+		1092 4905  SpeedStar A200
 		1092 4a09  Stealth III S540
 		1092 4a0b  Stealth III S540 Xtreme
 		1092 4a0f  Stealth III S540
 		1092 4e01  Stealth III S540
 		1102 101d  3d Blaster Savage 4
 		1102 101e  3d Blaster Savage 4
+		5333 8100  86C394-397 Savage4 SDRAM 100
+		5333 8110  86C394-397 Savage4 SDRAM 110
+		5333 8125  86C394-397 Savage4 SDRAM 125
+		5333 8143  86C394-397 Savage4 SDRAM 143
+		5333 8a22  86C394-397 Savage4
+		5333 8a2e  86C394-397 Savage4 32bit
+		5333 9125  86C394-397 Savage4 SGRAM 125
+		5333 9143  86C394-397 Savage4 SGRAM 143
 	8a23  Savage 4
 	8c00  ViRGE/M3
 	8c01  ViRGE/MX
 	8c02  ViRGE/MX+
 	8c03  ViRGE/MX+MV
+	8c10  86C270-294 Savage/MX-/IX
+	8c12  86C270-294 Savage/MX-/IX
+	9102  86C410 Savage 2000
+		1092 5932  Viper II Z200
+		1092 5934  Viper II Z200
+		1092 5952  Viper II Z200
+		1092 5954  Viper II Z200
+		1092 5a35  Viper II Z200
+		1092 5a37  Viper II Z200
+		1092 5a55  Viper II Z200
+		1092 5a57  Viper II Z200
 	ca00  SonicVibes
 544c  Teralogic Inc
 5455  Technische University Berlin
@@ -3402,6 +4371,7 @@
 		1014 0119  Netfinity Gigabit Ethernet SX Adapter
 		8086 1000  EtherExpress PRO/1000 Gigabit Server Adapter
 	1030  82559 InBusiness 10/100
+	1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller
 	1209  82559ER
 	1221  82092AA_0
 	1222  82092AA_1
@@ -3426,10 +4396,11 @@
 		1033 8000  PC-9821X-B06
 		1033 8016  PK-UG-X006
 		1033 801f  PK-UG-X006
-		103c 10C0  Ethernet Pro 10/100TX
-		103c 10C3  Ethernet Pro 10/100TX
+		103c 10c0  Ethernet Pro 10/100TX
+		103c 10c3  Ethernet Pro 10/100TX
 		103c 1200  Ethernet Pro 10/100TX
 		10c3 1100  SmartEther100 SC1100
+		1179 0002  PCI FastEther LAN on Docker
 		1259 2560  AT-2560 100 
 		1259 2561  AT-2560 100 FX Ethernet Adapter
 		1266 0001  NE10/100 Adapter
@@ -3448,7 +4419,7 @@
 		8086 000d  EtherExpress PRO/100+ Alert On LAN II* Adapter
 		8086 000e  EtherExpress PRO/100+ Management Adapter with Alert On LAN*
 		8086 1009  EtherExpress PRO/100+ Server Adapter
-		8086 100C  EtherExpress PRO/100+ Server Adapter (PILA8470B)
+		8086 100c  EtherExpress PRO/100+ Server Adapter (PILA8470B)
 		8086 10f0  EtherExpress PRO/100+ Dual Port Adapter
 		8086 200d  EtherExpress PRO/100 Cardbus
 		8086 200e  EtherExpress PRO/100 LAN+V90 Cardbus Modem
@@ -3465,21 +4436,30 @@
 	1239  82371FB
 	123b  82380PB
 	123c  82380AB
+	123d  683053 Programmable Interrupt Device
 	1240  752 AGP
 	124b  82380FB
 	1250  430HX - 82439HX TXC [Triton II]
+	1360  82806AA PCI64 Hub PCI Bridge
+	1361  82806AA PCI64 Hub Controller (HRes)
 	1960  80960RP [i960RP Microprocessor]
 		101e 0438  MegaRaid 438
 		101e 0466  MegaRaid 466
-		103c 10C6  MegaRaid 438
-		103c 10C7  MegaRaid T5
+		103c 10c6  MegaRaid 438
+		103c 10c7  MegaRaid T5
 		1111 1111  MegaRaid 466
-		113c 03A2  MegaRaid
+		113c 03a2  MegaRaid
+	1a21  82840 840 (Carmel) Chipset Host Bridge (Hub A)
+	1a23  82840 840 (Carmel) Chipset AGP Bridge
+	1a24  82840 840 (Carmel) Chipset PCI Bridge (Hub B)
 	2410  82801AA 82810 Chipset ISA Bridge (LPC)
 	2411  82801AA 82810 Chipset IDE
 	2412  82801AA 82810 Chipset USB
 	2413  82801AA 82810 Chipset SMBus
 	2415  82801AA 82810 AC'97 Audio
+		11d4 0040  SoundMAX Integrated Digital Audio
+		11d4 0048  SoundMAX Integrated Digital Audio
+		11d4 5340  SoundMAX Integrated Digital Audio
 	2416  82801AA 82810 AC'97 Modem
 	2418  82801AA 82810 PCI Bridge
 	2420  82801AB 82810 Chipset ISA Bridge (LPC)
@@ -3487,10 +4467,21 @@
 	2422  82801AB 82810 Chipset USB
 	2423  82801AB 82810 Chipset SMBus
 	2425  82801AB 82810 AC'97 Audio
+		11d4 0040  SoundMAX Integrated Digital Audio
+		11d4 0048  SoundMAX Integrated Digital Audio
 	2426  82801AB 82810 AC'97 Modem
 	2428  82801AB 82810 PCI Bridge
+	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
+		1043 801c  P3C-2000 system chipset
+	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
+		1043 801c  P3C-2000 system chipset
+	250b  82820 820 (Camino) Chipset Host Bridge
+	250f  82820 820 (Camino) Chipset PCI to AGP Bridge
+	2520  82805AA MTH Memory Translator Hub
+	2521  82804AA MRH-S Memory Repeater Hub for SDRAM
 	5200  EtherExpress PRO/100
 	5201  EtherExpress PRO/100
+		8086 0001  EtherExpress PRO/100 Server Ethernet Adapter
 	7000  82371SB PIIX3 ISA [Natoma/Triton II]
 	7010  82371SB PIIX3 IDE [Natoma/Triton II]
 	7020  82371SB PIIX3 USB [Natoma/Triton II]
@@ -3506,6 +4497,7 @@
 	7123  82810-DC100 CGC [Chipset Graphics Controller]
 	7124  82810E GMCH [Graphics Memory Controller Hub]
 	7125  82810E CGC [Chipset Graphics Controller]
+	7126  82810 810 Chipset Host Bridge and Memory Controller Hub
 	7180  440LX/EX - 82443LX/EX Host bridge
 	7181  440LX/EX - 82443LX/EX AGP bridge
 	7190  440BX/ZX - 82443BX/ZX Host bridge
@@ -3513,11 +4505,22 @@
 	7191  440BX/ZX - 82443BX/ZX AGP bridge
 	7192  440BX/ZX - 82443BX/ZX Host bridge (AGP disabled)
 		0e11 0460  Armada 1700 Laptop System Chipset
+	7194  82440MX I/O Controller
+	7195  82440MX AC'97 Audio Controller
+		10cf 1099  QSound_SigmaTel Stac97 PCI Audio
+		11d4 0040  SoundMAX Integrated Digital Audio
+		11d4 0048  SoundMAX Integrated Digital Audio
+	7198  82440MX PCI to ISA Bridge
+	7199  82440MX EIDE Controller
+	719a  82440MX USB Universal Host Controller
+	719b  82440MX Power Management Controller
 	71a0  440GX - 82443GX Host bridge
 	71a1  440GX - 82443GX AGP bridge
 	71a2  440GX - 82443GX Host bridge (AGP disabled)
+	7600  82372FB PCI to ISA Bridge
 	7601  82372FB PIIX4 IDE
 	7602  82372FB [PCI-to-USB UHCI]
+	7603  82372FB System Management Bus Controller
 	7800  i740
 		1092 0100  Stealth II G460
 		8086 0100  Intel740 Graphics Accelerator
@@ -3542,6 +4545,7 @@
 	3b78  AHA-4844W/4844UW
 	5075  AIC-755x
 	5078  AHA-7850
+		9004 7850  AHA-2904/Integrated AIC-7850
 	5175  AIC-755x
 	5178  AIC-7851
 	5275  AIC-755x
@@ -3560,10 +4564,10 @@
 	5900  ANA-5910/5930/5940 ATM155 & 25 LAN Adapter
 	5905  ANA-5910A/5930A/5940A ATM Adapter
 	6038  AIC-3860
-# FIXME: This is a cardbus card.  The declaration may be duplicative.
 	6075  AIC-1480 / APA-1480
 	6078  AIC-7860
 	6178  AIC-7861
+		9004 7861  AHA-2940AU Single
 	6278  AIC-7860
 	6378  AIC-7860
 	6478  AIC-786
@@ -3593,6 +4597,9 @@
 	7678  AHA-4944W/UW / 7876
 	7778  AIC-787x
 	7810  AIC-7810
+	7815  AIC-7815 RAID+Memory Controller IC
+		9004 7815  ARO-1130U2 RAID Controller
+		9004 7840  AIC-7815 RAID+Memory Controller IC
 	7850  AIC-7850
 	7855  AHA-2930
 	7860  AIC-7860
@@ -3608,16 +4615,20 @@
 	7893  AIC-789x
 	7894  AIC-789x
 	7895  AHA-2940U/UW / AHA-39xx / AIC-7895
+		9004 7895  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
 	7896  AIC-789x
 	7897  AIC-789x
 	8078  AIC-7880U
+		9004 7880  AIC-7880P Ultra/Ultra Wide SCSI Chipset
 	8178  AIC-7881U
+		9004 7881  AHA-2940UW SCSI Host Adapter
 	8278  AHA-3940U/UW / AIC-7882U
 	8378  AHA-3940U/UW / AIC-7883U
 	8478  AHA-294x / AIC-7884U
 	8578  AHA-3944U / AHA-3944UWD / 7885
 	8678  AHA-4944UW / 7886
 	8778  AIC-788x
+		9004 7887  2940UW Pro Ultra-Wide SCSI Controller
 	8878  7888
 	8b78  ABA-1030
 	ec78  AHA-4944W/UW
@@ -3625,13 +4636,18 @@
 	0010  AHA-2940U2/W
 	0011  2930U2
 	0013  78902
+		9005 0003  AAA-131U2 Array1000 1 Channel RAID Controller
 	001f  AHA-2940U2/W / 7890
+		9005 000f  2940U2W SCSI Controller
+		9005 a180  2940U2W SCSI Controller
 	0020  AIC-7890
 	002f  AIC-7890
 	0030  AIC-7890
 	003f  AIC-7890
 	0050  3940U2
 	0051  3950U2D
+	0053  AIC-7896 SCSI Controller
+		9005 ffff  AIC-7896 SCSI Controller mainboard implementation
 	005f  7896
 	0080  7892A
 	0081  7892B
@@ -3643,8 +4659,11 @@
 	00cf  7899P
 907f  Atronics
 	2015  IDE-2015PL
+919a  Gigapixel Corp
 9412  Holtek
 	6565  6565
+9699  Omni Media Technology Inc
+	6565  6565
 a0a0  AOPEN Inc.
 a0f1  UNISYS Corporation
 a200  NEC Corporation
@@ -3653,14 +4672,17 @@
 a304  Sony
 a727  3Com Corporation
 aa42  Scitex Digital Video
+ac1e  Digital Receiver Technology Inc
 b1b3  Shiva Europe Limited
 c001  TSI Telsys
 c0a9  Micron/Crucial Technology
 c0de  Motorola
 c0fe  Motion Engineering, Inc.
+ca50  Varian Australia Pty Ltd
 cafe  Chrysalis-ITS
 cccc  Catapult Communications
 d4d4  Dy4 Systems Inc
+	0601  PCI Mezzanine Card
 d84d  Exsys
 e000  Winbond
 	e000  W89C940
@@ -3669,6 +4691,7 @@
 		0059 0001  128k ISDN-S/T Adapter
 		0059 0003  128k ISDN-U Adapter
 e4bf  EKF Elektronik GmbH
+ea01  Eagle Technology
 eabb  Aashima Technology B.V.
 ecc0  Echo Corporation
 edd8  ARK Logic Inc
@@ -3676,6 +4699,7 @@
 	a099  2000PV [Stingray]
 	a0a1  2000MT
 	a0a9  2000MI
+fa57  Fast Search & Transfer ASA
 feda  Epigram Inc
 fffe  VMWare Inc
 	0710  Virtual SVGA
@@ -3685,9 +4709,9 @@
 # List of known device classes, subclasses and programming interfaces
 
 # Syntax:
-# C class  class_name
-#	subclass  subclass_name			<-- single tab
-#		prog-if  prog-if_name		<-- two tabs
+# C class	class_name
+#	subclass	subclass_name  		<-- single tab
+#		prog-if  prog-if_name  	<-- two tabs
 
 C 00  Unclassified device
 	00  Non-VGA unclassified device
@@ -3750,7 +4774,7 @@
 		01  BiDir
 		02  ECP
 		03  IEEE1284
-		FE  IEEE1284 Target
+		fe  IEEE1284 Target
 	02  Multiport serial controller
 	03  Modem
 		00  Generic
@@ -3788,10 +4812,10 @@
 		00  Generic
 		10  Extended
 	80  Input device controller
-C 0A  Docking station
+C 0a  Docking station
 	00  Generic Docking Station
 	80  Docking Station
-C 0B  Processor
+C 0b  Processor
 	00  386
 	01  486
 	02  Pentium
@@ -3799,7 +4823,7 @@
 	20  Power PC
 	30  MIPS
 	40  Co-processor
-C 0C  Serial bus controller
+C 0c  Serial bus controller
 	00  FireWire (IEEE 1394)
 		00  Generic
 		10  OHCI
@@ -3809,17 +4833,17 @@
 		00  UHCI
 		10  OHCI
 		80  Unspecified
-		FE  USB Device
+		Fe  USB Device
 	04  Fiber Channel
 	05  SMBus
-C 0D  Wireless controller
+C 0d  Wireless controller
 	00  IRDA controller
 	01  Consumer IR controller
 	10  RF controller
 	80  Wireless controller
-C 0E  Intelligent controller
+C 0e  Intelligent controller
 	00  I2O
-C 0F  Satellite communications controller
+C 0f  Satellite communications controller
 	00  Satellite TV controller
 	01  Satellite audio communication controller
 	03  Satellite voice communication controller
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- v2.3.99-pre5/linux/drivers/pcmcia/ds.c	Thu Feb 10 17:11:12 2000
+++ linux/drivers/pcmcia/ds.c	Fri Apr 21 13:33:00 2000
@@ -669,6 +669,7 @@
 
 /*====================================================================*/
 
+/* No kernel lock - fine */
 static u_int ds_poll(struct file *file, poll_table *wait)
 {
     socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/jsflash.c linux/drivers/sbus/char/jsflash.c
--- v2.3.99-pre5/linux/drivers/sbus/char/jsflash.c	Thu Feb 10 17:11:12 2000
+++ linux/drivers/sbus/char/jsflash.c	Wed Apr 26 12:13:16 2000
@@ -3,11 +3,15 @@
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds	(drivers/char/mem.c)
  *  Copyright (C) 1997  Eddie C. Dost		(drivers/sbus/char/flash.c)
- *  Copyright (C) 1999  Pete Zaitcev
+ *  Copyright (C) 1997-2000 Pavel Machek <pavel@ucw.cz>   (drivers/block/nbd.c)
+ *  Copyright (C) 1999-2000 Pete Zaitcev
  *
  * This driver is used to program OS into a Flash SIMM on
  * Krups and Espresso platforms.
  *
+ * TODO: do not allow erase/programming if file systems are mounted.
+ * TODO: Erase/program both banks of a 8MB SIMM.
+ *
  * It is anticipated that programming an OS Flash will be a routine
  * procedure. In the same time it is exeedingly dangerous because
  * a user can program its OBP flash with OS image and effectively
@@ -31,23 +35,25 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#if 0	/* P3 from mem.c */
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/mman.h>
-#include <linux/random.h>
-#include <linux/raw.h>
-#include <linux/capability.h>
-#endif
+
+/*
+ * <linux/blk.h> is controlled from the outside with these definitions.
+ */
+#define MAJOR_NR	JSFD_MAJOR
+
+#define DEVICE_NAME "jsfd"
+#define DEVICE_REQUEST jsfd_do_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+#define DEVICE_NO_RANDOM
+
+#include <linux/blk.h>
+
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#if 0	/* P3 from mem.c */
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/ebus.h>
-#endif
 #include <asm/pcic.h>
 #include <asm/oplib.h>
 
@@ -58,8 +64,23 @@
 /*
  * Our device numbers have no business in system headers.
  * The only thing a user knows is the device name /dev/jsflash.
+ *
+ * Block devices are laid out like this:
+ *   minor+0	- Bootstrap, for 8MB SIMM 0x20400000[0x800000]
+ *   minor+1	- Filesystem to mount, normally 0x20400400[0x7ffc00]
+ *   minor+2	- Whole flash area for any case... 0x20000000[0x01000000]
+ * Total 3 minors per flash device.
+ *
+ * It is easier to have static size vectors, so we define
+ * a total minor range JSF_MAX, which must cover all minors.
  */
-#define JSF_MINOR	178
+/* character device */
+#define JSF_MINOR	178	/* 178 is registered with hpa */
+/* block device */
+#define JSF_MAX		 3	/* 3 minors wasted total so far. */
+#define JSF_NPART	 3	/* 3 minors per flash device */
+#define JSF_PART_BITS	 2	/* 2 bits of minors to cover JSF_NPART */
+#define JSF_PART_MASK	 0x3	/* 2 bits mask */
 
 /*
  * Access functions.
@@ -86,11 +107,20 @@
 /*
  * soft carrier
  */
+
+struct jsfd_part {
+	unsigned long dbase;
+	unsigned long dsize;
+	int refcnt;
+};
+
 struct jsflash {
 	unsigned long base;
 	unsigned long size;
 	unsigned long busy;		/* In use? */
 	struct jsflash_ident_arg id;
+	/* int mbase; */		/* Minor base, typically zero */
+	struct jsfd_part dv[JSF_NPART];
 };
 
 /*
@@ -103,6 +133,12 @@
 #define JSF_BASE_JK	0x20400000
 
 /*
+ */
+static int jsfd_blksizes[JSF_MAX];
+static int jsfd_sizes[JSF_MAX];
+static u64 jsfd_bytesizes[JSF_MAX];
+
+/*
  * Let's pretend we may have several of these...
  */
 static struct jsflash jsf0;
@@ -112,7 +148,7 @@
  * We use the Toggle bit DQ6 (0x40) because it does not
  * depend on the data value as /DATA bit DQ7 does.
  *
- * XXX Do we need any timeout here?
+ * XXX Do we need any timeout here? So far it never hanged, beware broken hw.
  */
 static void jsf_wait(unsigned long p) {
 	unsigned int x1, x2;
@@ -146,6 +182,73 @@
 }
 
 /*
+ */
+static void jsfd_read(char *buf, unsigned long p, size_t togo) {
+	union byte4 {
+		char s[4];
+		unsigned int n;
+	} b;
+
+	while (togo >= 4) {
+		togo -= 4;
+		b.n = jsf_inl(p);
+		memcpy(buf, b.s, 4);
+		p += 4;
+		buf += 4;
+	}
+}
+
+static void jsfd_do_request(request_queue_t *q)
+{
+	struct request *req;
+	int dev;
+	struct jsfd_part *jdp;
+	unsigned long offset;
+	size_t len;
+
+	for (;;) {
+		INIT_REQUEST;	/* if (QUEUE_EMPTY) return; */
+		req = CURRENT;
+
+		dev = MINOR(req->rq_dev);
+		if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) {
+			end_request(0);
+			continue;
+		}
+		jdp = &jsf0.dv[dev & JSF_PART_MASK];
+
+		offset = req->sector << 9;
+		len = req->current_nr_sectors << 9;
+		if ((offset + len) > jdp->dsize) {
+               		end_request(0);
+			continue;
+		}
+
+		if (req->cmd == WRITE) {
+			printk(KERN_ERR "jsfd: write\n");
+			end_request(0);
+			continue;
+		}
+		if (req->cmd != READ) {
+			printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd);
+			end_request(0);
+			continue;
+		}
+
+		if ((jdp->dbase & 0xff000000) != 0x20000000) {
+			printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase);
+			end_request(0);
+			continue;
+		}
+
+/* printk("jsfd%d: read buf %p off %x len %x\n", dev, req->buffer, (int)offset, (int)len); */ /* P3 */
+		jsfd_read(req->buffer, jdp->dbase + offset, len);
+
+		end_request(1);
+	}
+}
+
+/*
  * The memory devices use the full 32/64 bits of the offset, and so we cannot
  * check against negative addresses: they are ok. The return value is weird,
  * though, in that case (0).
@@ -301,7 +404,7 @@
 	if (verify_area(VERIFY_READ, uptr, togo))
 		return -EFAULT;
 	while (togo != 0) {
-		--togo;
+		togo -= 4;
 		copy_from_user(&b.s[0], uptr, 4);
 		jsf_write4(p, b.n);
 		p += 4;
@@ -316,6 +419,8 @@
 {
 	int error = -ENOTTY;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
 	switch (cmd) {
 	case JSFLASH_IDENT:
 		if (verify_area(VERIFY_WRITE, (void *)arg, JSFIDSZ))
@@ -334,6 +439,34 @@
 	return error;
 }
 
+static int jsfd_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+	int dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!inode)
+		return -EINVAL;
+	if ((dev = MINOR(inode->i_rdev)) >= JSF_MAX) return -ENODEV;
+
+	switch (cmd) {
+	case BLKGETSIZE:
+		return put_user(jsfd_bytesizes[dev] >> 9, (long *) arg);
+
+#if 0
+	case BLKROSET:
+	case BLKROGET:
+	case BLKSSZGET:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
+#endif
+
+	/* case BLKFLSBUF: */	/* Program, then read, what happens? Stale? */
+	default: ;
+	}
+	return -ENOTTY;
+}
+
 static int jsf_mmap(struct file * file, struct vm_area_struct * vma)
 {
 	return -ENXIO;
@@ -350,6 +483,26 @@
 	return 0;	/* XXX What security? */
 }
 
+static int jsfd_open(struct inode *inode, struct file *file)
+{
+	struct jsfd_part *jdp;
+	int dev;
+
+	if (!inode)
+		return -EINVAL;
+	dev = MINOR(inode->i_rdev);
+	if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) {
+		printk(KERN_ALERT "jsfd_open: illegal minor %d\n", dev);
+		return -ENODEV;
+	}
+
+	jdp = &jsf0.dv[dev];
+	jdp->refcnt++;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
 static int jsf_release(struct inode *inode, struct file *file)
 {
 
@@ -359,6 +512,30 @@
 	return 0;
 }
 
+static int jsfd_release(struct inode *inode, struct file *file)
+{
+	struct jsfd_part *jdp;
+	int dev;
+
+	if (!inode)
+		return -ENODEV;
+	dev = MINOR(inode->i_rdev);
+	if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) {
+		printk(KERN_ALERT "jsfd_release: illegal minor %d\n", dev);
+		return -ENODEV;
+	}
+
+	jdp = &jsf0.dv[dev];
+	if (jdp->refcnt <= 0) {
+		printk(KERN_ALERT "jsfd_release: bad ref on minor %d\n", dev);
+	} else {
+		--jdp->refcnt;
+	}
+	/* N.B. Doesn't lo->file need an fput?? */
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 static struct file_operations jsf_fops = {
 	llseek:		jsf_lseek,
 	read:		jsf_read,
@@ -371,37 +548,90 @@
 
 static struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops };
 
+static struct block_device_operations jsfd_fops = {
+	open:		jsfd_open,
+	release:	jsfd_release,
+	ioctl:		jsfd_ioctl,
+};
+
 EXPORT_NO_SYMBOLS;
 
-#ifdef MODULE
-int init_module(void)
-#else
-int __init jsflash_init(void)
-#endif
+int jsflash_init(void)
 {
 	int rc;
+	struct jsflash *jsf;
+	int node;
 	char banner[128];
+	struct linux_prom_registers reg0;
 
-	/* FIXME: Really autodetect things */
-	prom_getproperty(prom_root_node, "banner-name", banner, 128);
-	if (strcmp (banner, "JavaStation-NC") && strcmp (banner, "JavaStation-E"))
-		return -ENXIO;
-
-	/* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */
-	if (sparc_cpu_model == sun4m && jsf0.base == 0) {
-		/* XXX Autodetect */
+	node = prom_getchild(prom_root_node);
+	node = prom_searchsiblings(node, "flash-memory");
+	if (node != 0 && node != -1) {
+		if (prom_getproperty(node, "reg",
+		    (char *)&reg0, sizeof(reg0)) == -1) {
+			printk("jsflash: no \"reg\" property\n");
+			return -ENXIO;
+		}
+		if (reg0.which_io != 0) {
+			printk("jsflash: bus number nonzero: 0x%x:%x\n",
+			    reg0.which_io, reg0.phys_addr);
+			return -ENXIO;
+		}
 		/*
-		 * We do not want to use PROM properties;
-		 * They are faked by PROLL anyways.
+		 * Flash may be somewhere else, for instance on Ebus.
+		 * So, don't do the following check for IIep flash space.
 		 */
-		jsf0.base = JSF_BASE_JK;
-		jsf0.size = 0x00800000;		/* 8M */
+#if 0
+		if ((reg0.phys_addr >> 24) != 0x20) {
+			printk("jsflash: suspicious address: 0x%x:%x\n",
+			    reg0.which_io, reg0.phys_addr);
+			return -ENXIO;
+		}
+#endif
+		if ((int)reg0.reg_size <= 0) {
+			printk("jsflash: bad size 0x%x\n", (int)reg0.reg_size);
+			return -ENXIO;
+		}
+	} else {
+		/* XXX Remove this code once PROLL ID12 got widespread */
+		printk("jsflash: no /flash-memory node, use PROLL >= 12\n");
+		prom_getproperty(prom_root_node, "banner-name", banner, 128);
+		if (strcmp (banner, "JavaStation-NC") != 0 &&
+		    strcmp (banner, "JavaStation-E") != 0) {
+			return -ENXIO;
+		}
+		reg0.which_io = 0;
+		reg0.phys_addr = 0x20400000;
+		reg0.reg_size  = 0x00800000;
+	}
+
+	/* Let us be really paranoid for modifications to probing code. */
+	/* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */
+	if (sparc_cpu_model != sun4m) {
+		/* We must be on sun4m because we use MMU Bypass ASI. */
+		return -ENXIO;
+	}
+
+	if (jsf0.base == 0) {
+		jsf = &jsf0;
+
+		jsf->base = reg0.phys_addr;
+		jsf->size = reg0.reg_size;
 
-		jsf0.id.off = JSF_BASE_ALL;
-		jsf0.id.size = 0x01000000;	/* 16M - all segments */
-		strcpy(jsf0.id.name, "Krups_all");
+		/* XXX Redo the userland interface. */
+		jsf->id.off = JSF_BASE_ALL;
+		jsf->id.size = 0x01000000;	/* 16M - all segments */
+		strcpy(jsf->id.name, "Krups_all");
+
+		jsf->dv[0].dbase = jsf->base;
+		jsf->dv[0].dsize = jsf->size;
+		jsf->dv[1].dbase = jsf->base + 1024;
+		jsf->dv[1].dsize = jsf->size - 1024;
+		jsf->dv[2].dbase = JSF_BASE_ALL;
+		jsf->dv[2].dsize = 0x01000000;
 
-		printk("Espresso Flash @0x%lx\n", jsf0.base);
+		printk("Espresso Flash @0x%lx [%d MB]\n", jsf->base,
+		    (int) (jsf->size / (1024*1024)));
 	}
 
 	if ((rc = misc_register(&jsf_dev)) != 0) {
@@ -410,12 +640,63 @@
 		jsf0.base = 0;
 		return rc;
 	}
+
+	return 0;
+}
+
+int jsfd_init(void) {
+	struct jsflash *jsf;
+	struct jsfd_part *jdp;
+	int i;
+
+	if (jsf0.base == 0) {
+		printk("jsfd_init: no flash\n"); /* P3 */
+		return -EIO;
+	}
+
+	if (register_blkdev(JSFD_MAJOR, "jsfd", &jsfd_fops)) {
+		printk("jsfd_init: unable to get major number %d\n",
+		    JSFD_MAJOR);
+		return -EIO;
+	}
+
+	printk("jsfd0: at major %d\n", MAJOR_NR); /* P3 */
+
+	blksize_size[JSFD_MAJOR] = jsfd_blksizes;
+	blk_size[JSFD_MAJOR] = jsfd_sizes;
+
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+	/* blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); */
+	for (i = 0; i < JSF_MAX; i++) {
+		if ((i & JSF_PART_MASK) >= JSF_NPART) continue;
+		jsf = &jsf0;	/* actually, &jsfv[i >> JSF_PART_BITS] */
+		jdp = &jsf->dv[i&JSF_PART_MASK];
+
+		jdp->refcnt = 0;
+
+		jsfd_blksizes[i] = 1024;
+		jsfd_bytesizes[i] = jdp->dsize;
+		jsfd_sizes[i] = jsfd_bytesizes[i] >> 10;
+		register_disk(NULL, MKDEV(JSFD_MAJOR, i), 1, &jsfd_fops,
+				jsfd_bytesizes[i] >> 9);
+		set_device_ro(MKDEV(JSFD_MAJOR, i), 1);
+	}
 	return 0;
 }
 
 #ifdef MODULE
-void cleanup_module(void)
-{
+
+int init_module(void) {
+	int rc;
+
+	if ((rc = jsflash_init()) == 0) {
+		jsfd_init();
+		return 0;
+	}
+	return rc;
+}
+
+void cleanup_module(void) {
 
 	/* for (all probed units) {  } */
 	if (jsf0.busy)
@@ -424,5 +705,7 @@
 	jsf0.busy = 0;
 
 	misc_deregister(&jsf_dev);
+	if (unregister_blkdev(JSFD_MAJOR, "jsfd") != 0)
+		printk("jsfd: cleanup_module failed\n");
 }
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.3.99-pre5/linux/drivers/sbus/char/pcikbd.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/sbus/char/pcikbd.c	Mon Apr 24 13:59:58 2000
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.44 2000/02/11 04:49:13 davem Exp $
+/* $Id: pcikbd.c,v 1.45 2000/04/24 06:10:19 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -23,6 +23,7 @@
 #include <linux/kbd_ll.h>
 #include <linux/kbd_kern.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 #include <linux/init.h>
 
 #include <asm/ebus.h>
@@ -59,6 +60,8 @@
 static volatile unsigned char acknowledge = 0;
 static volatile unsigned char resend = 0;
 
+static spinlock_t pcikbd_lock = SPIN_LOCK_UNLOCKED;
+
 unsigned char pckbd_read_mask = KBD_STAT_OBF;
 
 extern int pcikbd_init(void);
@@ -71,26 +74,18 @@
 #define pcikbd_inb(x)     inb(x)
 #define pcikbd_outb(v,x)  outb(v,x)
 
-#if 0 /* deadwood */
-static __inline__ unsigned char pcikbd_inb(unsigned long port)
-{
-	return inb(port);
-}
-
-static __inline__ void pcikbd_outb(unsigned char val, unsigned long port)
-{
-	outb(val, port);
-}
-#endif
-
-static inline void kb_wait(void)
+/* Wait for keyboard controller input buffer to drain.
+ * Must be invoked under the pcikbd_lock.
+ */
+static void kb_wait(void)
 {
-	unsigned long start = jiffies;
+	unsigned long timeout = 250;
 
 	do {
 		if(!(pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF))
 			return;
-	} while (jiffies - start < KBC_TIMEOUT);
+		mdelay(1);
+	} while (--timeout);
 }
 
 /*
@@ -312,8 +307,11 @@
 static void
 pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	unsigned long flags;
 	unsigned char status;
 
+	spin_lock_irqsave(&pcikbd_lock, flags);
+
 	kbd_pt_regs = regs;
 	status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
 	do {
@@ -327,27 +325,45 @@
 		status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
 	} while(status & KBD_STAT_OBF);
 	tasklet_schedule(&keyboard_tasklet);
+
+	spin_unlock_irqrestore(&pcikbd_lock, flags);
 }
 
 static int send_data(unsigned char data)
 {
 	int retries = 3;
-	unsigned long start;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcikbd_lock, flags);
 
 	do {
+		unsigned long timeout = 1000;
+
 		kb_wait();
-		acknowledge = resend = 0;
+
+		acknowledge = 0;
+		resend = 0;
 		reply_expected = 1;
+
 		pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG);
-		start = jiffies;
 		do {
-			if(acknowledge)
-				return 1;
-			if(jiffies - start >= KBD_TIMEOUT)
-				return 0;
-		} while(!resend);
-	} while(retries-- > 0);
+			if (acknowledge)
+				goto out_ack;
+			if (resend)
+				break;
+			mdelay(1);
+		} while (--timeout);
+		if (timeout == 0)
+			goto out_timeout;
+	} while (retries-- > 0);
+
+out_timeout:
+	spin_unlock_irqrestore(&pcikbd_lock, flags);
 	return 0;
+
+out_ack:
+	spin_unlock_irqrestore(&pcikbd_lock, flags);
+	return 1;
 }
 
 void pcikbd_leds(unsigned char leds)
@@ -360,17 +376,23 @@
 static int __init pcikbd_wait_for_input(void)
 {
 	int status, data;
-	unsigned long start = jiffies;
+	unsigned long timeout = 1000;
 
 	do {
+		mdelay(1);
+
 		status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
-		if(!(status & KBD_STAT_OBF))
+		if (!(status & KBD_STAT_OBF))
 			continue;
+
 		data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);
-		if(status & (KBD_STAT_GTO | KBD_STAT_PERR))
+		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
 			continue;
+
 		return (data & 0xff);
-	} while(jiffies - start < KBD_INIT_TIMEOUT);
+
+	} while (--timeout > 0);
+
 	return -1;
 }
 
@@ -573,27 +595,12 @@
 };
 
 static struct aux_queue *queue;
-static int aux_ready = 0;
 static int aux_count = 0;
 static int aux_present = 0;
 
 #define pcimouse_inb(x)     inb(x)
 #define pcimouse_outb(v,x)  outb(v,x)
 
-#if 0
-
-static __inline__ unsigned char pcimouse_inb(unsigned long port)
-{
-	return inb(port);
-}
-
-static __inline__ void pcimouse_outb(unsigned char val, unsigned long port)
-{
-	outb(val, port);
-}
-
-#endif
-
 /*
  *	Shared subroutines
  */
@@ -603,11 +610,11 @@
 	unsigned int result;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&pcikbd_lock, flags);
 	result = queue->buf[queue->tail];
 	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&pcikbd_lock, flags);
+
 	return result;
 }
 
@@ -645,17 +652,17 @@
 
 static int poll_aux_status(void)
 {
-	int retries=0;
+	int retries = 0;
 
 	while ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) &
 		(KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) {
  		if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF)
 		    == AUX_STAT_OBF)
 			pcimouse_inb(pcimouse_iobase + KBD_DATA_REG);
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout((5*HZ + 99) / 100);
+		mdelay(5);
 		retries++;
 	}
+
 	return (retries < MAX_RETRIES);
 }
 
@@ -699,51 +706,38 @@
 }
 
 /*
- * AUX handler critical section start and end.
- * 
- * Only one process can be in the critical section and all keyboard sends are
- * deferred as long as we're inside. This is necessary as we may sleep when
- * waiting for the keyboard controller and other processes / BH's can
- * preempt us. Please note that the input buffer must be flushed when
- * aux_end_atomic() is called and the interrupt is no longer enabled as not
- * doing so might cause the keyboard driver to ignore all incoming keystrokes.
- */
-
-static DECLARE_MUTEX(aux_sema4);
-
-static inline void aux_start_atomic(void)
-{
-	down(&aux_sema4);
-	tasklet_disable_nosync(&keyboard_tasklet);
-	tasklet_unlock_wait(&keyboard_tasklet);
-}
-
-static inline void aux_end_atomic(void)
-{
-	tasklet_enable(&keyboard_tasklet);
-	up(&aux_sema4);
-}
-
-/*
  * Interrupt from the auxiliary device: a character
  * is waiting in the keyboard/aux controller.
  */
 
 void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int head = queue->head;
-	int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
+	unsigned long flags;
+	int head, maxhead;
+	unsigned char val;
 
-	if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF)
+	spin_lock_irqsave(&pcikbd_lock, flags);
+
+	head = queue->head;
+	maxhead = (queue->tail - 1) & (AUX_BUF_SIZE - 1);
+
+	if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) !=
+	    AUX_STAT_OBF) {
+		spin_unlock_irqrestore(&pcikbd_lock, flags);
 		return;
+	}
 
-	add_mouse_randomness(queue->buf[head] = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG));
+	val = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG);
+	queue->buf[head] = val;
+	add_mouse_randomness(val);
 	if (head != maxhead) {
 		head++;
-		head &= AUX_BUF_SIZE-1;
+		head &= AUX_BUF_SIZE - 1;
 	}
 	queue->head = head;
-	aux_ready = 1;
+
+	spin_unlock_irqrestore(&pcikbd_lock, flags);
+
 	if (queue->fasync)
 		kill_fasync(queue->fasync, SIGIO, POLL_IN);
 	wake_up_interruptible(&queue->proc_list);
@@ -751,10 +745,13 @@
 
 static int aux_release(struct inode * inode, struct file * file)
 {
+	unsigned long flags;
+
 	aux_fasync(-1, file, 0);
 	if (--aux_count)
 		return 0;
-	aux_start_atomic();
+
+	spin_lock_irqsave(&pcikbd_lock, flags);
 
 	/* Disable controller ints */
 	aux_write_cmd(AUX_INTS_OFF);
@@ -763,7 +760,8 @@
 	/* Disable Aux device */
 	pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG);
 	poll_aux_status();
-	aux_end_atomic();
+
+	spin_unlock_irqrestore(&pcikbd_lock, flags);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -776,17 +774,19 @@
 
 static int aux_open(struct inode * inode, struct file * file)
 {
+	unsigned long flags;
+
 	if (!aux_present)
 		return -ENODEV;
 
-	aux_start_atomic();
-	if (aux_count++) {
-		aux_end_atomic();
+	if (aux_count++)
 		return 0;
-	}
-	if (!poll_aux_status()) {		/* FIXME: Race condition */
+
+	spin_lock_irqsave(&pcikbd_lock, flags);
+
+	if (!poll_aux_status()) {
 		aux_count--;
-		aux_end_atomic();
+		spin_unlock_irqrestore(&pcikbd_lock, flags);
 		return -EBUSY;
 	}
 	queue->head = queue->tail = 0;		/* Flush input queue */
@@ -798,9 +798,10 @@
 	aux_write_dev(AUX_ENABLE_DEV);			    /* Enable aux device */
 	aux_write_cmd(AUX_INTS_ON);			    /* Enable controller ints */
 	poll_aux_status();
-	aux_end_atomic();
 
-	aux_ready = 0;
+	spin_unlock_irqrestore(&pcikbd_lock, flags);
+
+
 	return 0;
 }
 
@@ -812,23 +813,35 @@
 			 size_t count, loff_t *ppos)
 {
 	ssize_t retval = 0;
+	unsigned long flags;
 
 	if (count) {
 		ssize_t written = 0;
 
-		aux_start_atomic();
+		spin_lock_irqsave(&pcikbd_lock, flags);
+
 		do {
 			char c;
+
+			spin_unlock_irqrestore(&pcikbd_lock, flags);
+
+			get_user(c, buffer++);
+
+			spin_lock_irqsave(&pcikbd_lock, flags);
+
 			if (!poll_aux_status())
 				break;
-			pcimouse_outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG);
+			pcimouse_outb(KBD_CCMD_WRITE_MOUSE,
+				      pcimouse_iobase + KBD_CNTL_REG);
 			if (!poll_aux_status())
 				break;
-			get_user(c, buffer++);
+
 			pcimouse_outb(c, pcimouse_iobase + KBD_DATA_REG);
 			written++;
 		} while (--count);
-		aux_end_atomic();
+
+		spin_unlock_irqrestore(&pcikbd_lock, flags);
+
 		retval = -EIO;
 		if (written) {
 			retval = written;
@@ -872,7 +885,6 @@
 		put_user(c, buffer++);
 		i--;
 	}
-	aux_ready = !queue_empty();
 	if (count-i) {
 		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 		return count-i;
@@ -885,7 +897,7 @@
 static unsigned int aux_poll(struct file *file, poll_table * wait)
 {
 	poll_wait(file, &queue->proc_list, wait);
-	if (aux_ready)
+	if (!queue_empty())
 		return POLLIN | POLLRDNORM;
 	return 0;
 }
@@ -972,7 +984,9 @@
 	pckbd_read_mask = AUX_STAT_OBF;
 
 	misc_register(&psaux_mouse);
-	aux_start_atomic();
+
+	spin_lock_irq(&pcikbd_lock);
+
 	pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG);
 	aux_write_ack(AUX_RESET);
 	aux_write_ack(AUX_SET_SAMPLE);
@@ -987,7 +1001,8 @@
 	poll_aux_status();
 	pcimouse_outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG);
 	poll_aux_status();
-	aux_end_atomic();
+
+	spin_unlock_irq(&pcikbd_lock);
 
 	return 0;
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.3.99-pre5/linux/drivers/sbus/char/sab82532.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sbus/char/sab82532.c	Wed Apr 26 12:13:16 2000
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.41 2000/03/13 03:54:17 davem Exp $
+/* $Id: sab82532.c,v 1.44 2000/04/26 09:36:32 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -176,12 +176,22 @@
 
 #define NR_EBRG_VALUES	(sizeof(ebrg_table)/sizeof(struct ebrg_struct))
 
-#define SAB82532_MAX_TEC_DELAY	2000	/* 2 ms */
+#define SAB82532_MAX_TEC_TIMEOUT 200000	/* 1 character time (at 50 baud) */
+#define SAB82532_MAX_CEC_TIMEOUT  50000	/* 2.5 TX CLKs (at 50 baud) */
 
 static __inline__ void sab82532_tec_wait(struct sab82532 *info)
 {
-	int count = SAB82532_MAX_TEC_DELAY;
-	while ((readb(&info->regs->r.star) & SAB82532_STAR_TEC) && --count)
+	int timeout = info->tec_timeout;
+
+	while ((readb(&info->regs->r.star) & SAB82532_STAR_TEC) && --timeout)
+		udelay(1);
+}
+
+static __inline__ void sab82532_cec_wait(struct sab82532 *info)
+{
+	int timeout = info->cec_timeout;
+
+	while ((readb(&info->regs->r.star) & SAB82532_STAR_CEC) && --timeout)
 		udelay(1);
 }
 
@@ -209,8 +219,7 @@
 	}
 
 	/* Issue a Transmit Frame command. */
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr);
 
 out:
@@ -277,8 +286,7 @@
 	tmp = readb(&info->regs->rw.rfc);
 	tmp &= ~(SAB82532_RFC_RFDF);
 	writeb(tmp, &info->regs->rw.rfc);
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);
 
 #ifndef __sparc_v9__
@@ -293,8 +301,7 @@
 	 * Reset FIFO to character + status mode.
 	 */
 	writeb(saved_rfc, &info->regs->w.rfc);
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);
 }
 
@@ -345,16 +352,19 @@
 		free_fifo++;
 	}
 
-	if (stat->sreg.isr0 & SAB82532_ISR0_TCD) {
-		count = readb(&info->regs->r.rbcl) & (info->recv_fifo_size - 1);
-		free_fifo++;
-	}
-
 	/* Issue a FIFO read command in case we where idle. */
 	if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
-		if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-			udelay(1);
+		sab82532_cec_wait(info);
 		writeb(SAB82532_CMDR_RFRD, &info->regs->w.cmdr);
+		/* Wait for command execution, to catch the TCD below. */
+		sab82532_cec_wait(info);
+	}
+
+	if (stat->sreg.isr0 & SAB82532_ISR0_TCD) {
+		count = readb(&info->regs->r.rbcl) & (info->recv_fifo_size - 1);
+		if (count == 0)
+			count = info->recv_fifo_size;
+		free_fifo++;
 	}
 
 	if (stat->sreg.isr0 & SAB82532_ISR0_RFO) {
@@ -370,8 +380,7 @@
 
 	/* Issue Receive Message Complete command. */
 	if (free_fifo) {
-		if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-			udelay(1);
+		sab82532_cec_wait(info);
 		writeb(SAB82532_CMDR_RMC, &info->regs->w.cmdr);
 	}
 
@@ -451,8 +460,7 @@
 	}
 
 	/* Issue a Transmit Frame command. */
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr);
 
 	if (info->xmit_cnt < WAKEUP_CHARS)
@@ -709,18 +717,14 @@
 	/*
 	 * Wait for any commands or immediate characters
 	 */
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	sab82532_tec_wait(info);
 
 	/*
 	 * Clear the FIFO buffers.
 	 */
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
 	writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	writeb(SAB82532_CMDR_XRES, &info->regs->w.cmdr);
 
 	/*
@@ -997,10 +1001,15 @@
 	ebrg |= (ebrg_table[i].m << 6);
 
 	info->baud = ebrg_table[i].baud;
-	if (info->baud)
+	if (info->baud) {
 		info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
-	else
+		info->tec_timeout = (10 * 1000000) / info->baud;
+		info->cec_timeout = info->tec_timeout >> 2;
+	} else {
 		info->timeout = 0;
+		info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
+		info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
+	}
 	info->timeout += HZ / 50;		/* Add .02 seconds of slop */
 
 	/* CTS flow control flags */
@@ -1037,8 +1046,7 @@
 					    SAB82532_ISR0_TIME;
 
 	save_flags(flags); cli();
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	sab82532_tec_wait(info);
 	writeb(dafo, &info->regs->w.dafo);
 	writeb(ebrg & 0xff, &info->regs->w.bgr);
@@ -2092,7 +2100,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -2163,7 +2171,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.41 $";
+	char *revision = "$Revision: 1.44 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2196,7 +2204,11 @@
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
 	serial_driver.driver_name = "serial";
+#ifdef CONFIG_DEVFS_FS
 	serial_driver.name = "tts/%d";
+#else
+	serial_driver.name = "ttyS";
+#endif
 	serial_driver.major = TTY_MAJOR;
 	serial_driver.minor_start = 64 + su_num_ports;
 	serial_driver.num = NR_PORTS;
@@ -2267,6 +2279,8 @@
 		info->custom_divisor = 16;
 		info->close_delay = 5*HZ/10;
 		info->closing_wait = 30*HZ;
+		info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
+		info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
 		info->x_char = 0;
 		info->event = 0;	
 		info->blocked_open = 0;
@@ -2550,8 +2564,7 @@
 		info->flags |= ASYNC_CHECK_CD;
 
 	save_flags(flags); cli();
-	if (readb(&info->regs->r.star) & SAB82532_STAR_CEC)
-		udelay(1);
+	sab82532_cec_wait(info);
 	sab82532_tec_wait(info);
 	writeb(dafo, &info->regs->w.dafo);
 	writeb(ebrg & 0xff, &info->regs->w.bgr);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.3.99-pre5/linux/drivers/sbus/char/su.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sbus/char/su.c	Mon Apr 24 13:59:58 2000
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.37 2000/03/13 03:54:15 davem Exp $
+/* $Id: su.c,v 1.38 2000/04/22 00:45:16 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2204,7 +2204,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -2223,7 +2223,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.37 $";
+	char *revision = "$Revision: 1.38 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.3.99-pre5/linux/drivers/sbus/char/sunkbd.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/sbus/char/sunkbd.c	Mon Apr 24 13:59:58 2000
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sysrq.h>
+#include <linux/spinlock.h>
 #include <linux/devfs_fs_kernel.h>
 
 #include <asm/kbio.h>
@@ -90,6 +91,8 @@
 	return 0;
 }
 
+static spinlock_t sunkbd_lock = SPIN_LOCK_UNLOCKED;
+
 /*
  * global state includes the following, and various static variables
  * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
@@ -255,6 +258,7 @@
 static void nop_kbd_put_char(unsigned char c) { }
 static void (*kbd_put_char)(unsigned char) = nop_kbd_put_char;
 
+/* Must be invoked under sunkbd_lock. */
 static inline void send_cmd(unsigned char c)
 {
 	kbd_put_char(c);
@@ -429,6 +433,7 @@
 	    e0_keys[scancode - 128];
 }
 
+static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs);
 void sunkbd_inchar(unsigned char ch, struct pt_regs *regs);
 static void keyboard_timer (unsigned long ignored);
 
@@ -443,16 +448,17 @@
 {
 	unsigned long flags;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&sunkbd_lock, flags);
 
 	/* Auto repeat: send regs = 0 to indicate autorepeat */
-	sunkbd_inchar (last_keycode, 0);
+	__sunkbd_inchar (last_keycode, 0);
 	del_timer (&auto_repeat_timer);
 	if (kbd_rate_ticks) {
 		auto_repeat_timer.expires = jiffies + kbd_rate_ticks;
 		add_timer (&auto_repeat_timer);
 	}
-	restore_flags(flags);
+
+	spin_unlock_irqrestore(&sunkbd_lock, flags);
 }
 
 #ifndef CONFIG_PCI
@@ -460,8 +466,10 @@
 #endif
 
 /* #define SKBD_DEBUG */
-/* This is our keyboard 'interrupt' routine. */
-void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
+/* This is our keyboard 'interrupt' routine.
+ * Must run under sunkbd_lock.
+ */
+static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
 {
 	unsigned char keycode;
 	char up_flag;                          /* 0 or SUNKBD_UBIT */
@@ -612,6 +620,15 @@
 	tasklet_schedule(&keyboard_tasklet);
 }
 
+void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sunkbd_lock, flags);
+	__sunkbd_inchar(ch, regs);
+	spin_unlock_irqrestore(&sunkbd_lock, flags);
+}
+
 static void put_queue(int ch)
 {
 	wake_up(&keypress_wait);
@@ -1164,15 +1181,21 @@
 static unsigned char sunkbd_ledstate = 0xff; /* undefined */
 void sun_kbd_bh(unsigned long dummy)
 {
-	unsigned char leds = getleds();
-	unsigned char kbd_leds = vcleds_to_sunkbd(leds);
+	unsigned long flags;
+	unsigned char leds, kbd_leds;
+
+	spin_lock_irqsave(&sunkbd_lock, flags);
 
+	leds = getleds();
+	kbd_leds = vcleds_to_sunkbd(leds);
 	if (kbd_leds != sunkbd_ledstate) {
 		ledstate = leds;
 		sunkbd_ledstate = kbd_leds;
 		send_cmd(SKBDCMD_SETLED);
 		send_cmd(kbd_leds);
 	}
+
+	spin_unlock_irqrestore(&sunkbd_lock, flags);
 }
 
 /* Support for keyboard "beeps". */ 
@@ -1180,7 +1203,11 @@
 /* Timer routine to turn off the beep after the interval expires. */
 static void sunkbd_kd_nosound(unsigned long __unused)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&sunkbd_lock, flags);
 	send_cmd(SKBDCMD_BELLOFF);
+	spin_unlock_irqrestore(&sunkbd_lock, flags);
 }
 
 /*
@@ -1195,8 +1222,7 @@
 	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
 						 sunkbd_kd_nosound };
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&sunkbd_lock, flags);
 
 	del_timer(&sound_timer);
 
@@ -1209,7 +1235,7 @@
 	} else
 		send_cmd(SKBDCMD_BELLOFF);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&sunkbd_lock, flags);
 }
 
 extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
@@ -1260,6 +1286,7 @@
 #define KBD_QSIZE 32
 static Firm_event kbd_queue [KBD_QSIZE];
 static int kbd_head, kbd_tail;
+static spinlock_t kbd_queue_lock = SPIN_LOCK_UNLOCKED;
 char kbd_opened;
 static int kbd_active = 0;
 static DECLARE_WAIT_QUEUE_HEAD(kbd_wait);
@@ -1268,16 +1295,22 @@
 void
 push_kbd (int scan)
 {
-	int next = (kbd_head + 1) % KBD_QSIZE;
+	unsigned long flags;
+	int next;
 
 	if (scan == KBD_IDLE)
 		return;
+
+	spin_lock_irqsave(&kbd_queue_lock, flags);
+	next = (kbd_head + 1) % KBD_QSIZE;
 	if (next != kbd_tail){
 		kbd_queue [kbd_head].id = scan & KBD_KEYMASK;
 		kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN;
 		kbd_queue [kbd_head].time = xtime;
 		kbd_head = next;
 	}
+	spin_unlock_irqrestore(&kbd_queue_lock, flags);
+
 	if (kb_fasync)
 		kill_fasync (kb_fasync, SIGIO, POLL_IN);
 	wake_up_interruptible (&kbd_wait);
@@ -1287,6 +1320,7 @@
 kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos)
 {
 	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
 	char *end, *p;
 
 	/* Return EWOULDBLOCK, because this is what the X server expects */
@@ -1294,9 +1328,11 @@
 		if (f->f_flags & O_NONBLOCK)
 			return -EWOULDBLOCK;
 		add_wait_queue (&kbd_wait, &wait);
-		while (kbd_head == kbd_tail && !signal_pending(current)) {
-			current->state = TASK_INTERRUPTIBLE;
-			schedule ();
+repeat:
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (kbd_head == kbd_tail && !signal_pending(current)) {
+			schedule();
+			goto repeat;
 		}
 		current->state = TASK_RUNNING;
 		remove_wait_queue (&kbd_wait, &wait);
@@ -1304,29 +1340,40 @@
 	/* There is data in the keyboard, fill the user buffer */
 	end = buffer+count;
 	p = buffer;
+	spin_lock_irqsave(&kbd_queue_lock, flags);
 	for (; p < end && kbd_head != kbd_tail;){
+		Firm_event this_event = kbd_queue[kbd_tail];
+
+		kbd_tail = (kbd_tail + 1) % KBD_QSIZE;
+
+		spin_unlock_irqrestore(&kbd_queue_lock, flags);
+
 #ifdef CONFIG_SPARC32_COMPAT
 		if (current->thread.flags & SPARC_FLAG_32BIT) {
-			copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], 
-					 sizeof(Firm_event)-sizeof(struct timeval), -EFAULT);
+			copy_to_user_ret((Firm_event *)p, &this_event,
+					 sizeof(Firm_event)-sizeof(struct timeval),
+					 -EFAULT);
 			p += sizeof(Firm_event)-sizeof(struct timeval);
-			__put_user_ret(kbd_queue[kbd_tail].time.tv_sec, (u32 *)p, -EFAULT);
+			__put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT);
 			p += sizeof(u32);
-			__put_user_ret(kbd_queue[kbd_tail].time.tv_usec, (u32 *)p, -EFAULT);
+			__put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT);
 			p += sizeof(u32);
 		} else
 #endif
 		{
-			copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], 
+			copy_to_user_ret((Firm_event *)p, &this_event, 
 					 sizeof(Firm_event), -EFAULT);
 			p += sizeof (Firm_event);
 		}
 #ifdef KBD_DEBUG
-		printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN");
+		printk ("[%s]", this_event.value == VKEY_UP ? "UP" : "DOWN");
 #endif
-		kbd_tail++;
-		kbd_tail %= KBD_QSIZE;
+
+		spin_lock_irqsave(&kbd_queue_lock, flags);
 	}
+
+	spin_unlock_irqrestore(&kbd_queue_lock, flags);
+
 	return p-buffer;
 }
 
@@ -1387,7 +1434,9 @@
 		switch (c) {
 			case SKBDCMD_CLICK:
 			case SKBDCMD_NOCLICK:
+				spin_lock_irq(&sunkbd_lock);
 				send_cmd(c);
+				spin_unlock_irq(&sunkbd_lock);
 				return 0;
 			case SKBDCMD_BELLON:
 				kd_mksound(1,0);
@@ -1469,7 +1518,11 @@
 		return 0;
 
 	kbd_opened = fg_console + 1;
+
+	spin_lock_irq(&kbd_queue_lock);
 	kbd_head = kbd_tail = 0;
+	spin_unlock_irq(&kbd_queue_lock);
+
 	return 0;
 }
 
@@ -1537,6 +1590,8 @@
 	if(sunkbd_type == SUNKBD_TYPE2)
 		sunkbd_clickp = 0;
 
+	spin_lock_irq(&sunkbd_lock);
+
 	if(sunkbd_clickp) {
 		send_cmd(SKBDCMD_CLICK);
 		printk("with keyclick\n");
@@ -1548,6 +1603,8 @@
 	/* Dork with led lights, then turn them all off */
 	send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */
 	send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */
+
+	spin_unlock_irq(&sunkbd_lock);
 
 	/* Register the /dev/kbd interface */
 	devfs_register (NULL, "kbd", 0, DEVFS_FL_NONE,
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v2.3.99-pre5/linux/drivers/sbus/char/sunmouse.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/sbus/char/sunmouse.c	Mon Apr 24 13:59:58 2000
@@ -48,6 +48,7 @@
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
 #include <linux/poll.h>
+#include <linux/spinlock.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -69,13 +70,13 @@
 	unsigned char prev_state;      /* Previous button state */
 	int delta_x;                   /* Current delta-x */
 	int delta_y;                   /* Current delta-y */
-	int ready;		       /* set if there if data is available */
 	int active;		       /* set if device is open */
         int vuid_mode;	               /* VUID_NATIVE or VUID_FIRM_EVENT */
 	wait_queue_head_t proc_list;
 	struct fasync_struct *fasync;
 	
 	/* The event/stream queue */
+	spinlock_t lock;
 	unsigned int head;
 	unsigned int tail;
 	union {
@@ -96,14 +97,22 @@
 static int
 push_event (Firm_event *ev)
 {
-	int next = (sunmouse.head + 1) % EV_SIZE;
+	unsigned long flags;
+	int next, ret;
 	
-	if (next != sunmouse.tail){
+	spin_lock_irqsave(&sunmouse.lock, flags);
+
+	next = (sunmouse.head + 1) % EV_SIZE;
+	ret = 0;
+	if (next != sunmouse.tail) {
 		sunmouse.queue.ev [sunmouse.head] = *ev;
 		sunmouse.head = next;
-		return 1;
+		ret = 1;
 	}
-	return 0;
+
+	spin_unlock_irqrestore(&sunmouse.lock, flags);
+
+	return ret;
 }
 
 static int
@@ -112,29 +121,32 @@
 	return sunmouse.head == sunmouse.tail;
 }
 
-static Firm_event *
-get_from_queue (void)
+/* Must be invoked under the sunmouse.lock */
+static void get_from_queue (Firm_event *p)
 {
-	Firm_event *result;
-	
-	result = &sunmouse.queue.ev [sunmouse.tail];
+	*p = sunmouse.queue.ev [sunmouse.tail];
 	sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
-	return result;
 }
 
 static void
 push_char (char c)
 {
-	int next = (sunmouse.head + 1) % STREAM_SIZE;
+	unsigned long flags;
+	int next;
 
-	if (next != sunmouse.tail){
+	spin_lock_irqsave(&sunmouse.lock, flags);
+
+	next = (sunmouse.head + 1) % STREAM_SIZE;
+	if (next != sunmouse.tail) {
 #ifdef SMOUSE_DEBUG
 		printk("P<%02x>\n", (unsigned char)c);
 #endif
 		sunmouse.queue.stream [sunmouse.head] = c;
 		sunmouse.head = next;
 	}
-	sunmouse.ready = 1;
+
+	spin_unlock_irqrestore(&sunmouse.lock, flags);
+
 	if (sunmouse.fasync)
 		kill_fasync (sunmouse.fasync, SIGIO, POLL_IN);
 	wake_up_interruptible (&sunmouse.proc_list);
@@ -325,24 +337,26 @@
 		sunmouse.byte = 69;  /* What could cause this? */
 		return;
 	};
-	if (!gen_events){
+
+	if (!gen_events) {
 		push_char (~sunmouse.button_state & 0x87);
 		push_char (sunmouse.delta_x);
 		push_char (sunmouse.delta_y);
 		return;
 	}
+
 	d = bstate ^ pstate;
 	pstate = bstate;
-	if (d){
-		if (d & BUTTON_LEFT){
+	if (d) {
+		if (d & BUTTON_LEFT) {
 			ev.id = MS_LEFT;
 			ev.value = bstate & BUTTON_LEFT;
 		}
-		if (d & BUTTON_RIGHT){
+		if (d & BUTTON_RIGHT) {
 			ev.id = MS_RIGHT;
 			ev.value = bstate & BUTTON_RIGHT;
 		}
-		if (d & BUTTON_MIDDLE){
+		if (d & BUTTON_MIDDLE) {
 			ev.id = MS_MIDDLE;
 			ev.value = bstate & BUTTON_MIDDLE;
 		}
@@ -350,25 +364,24 @@
 		ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
 		pushed += push_event (&ev);
 	}
-	if (sunmouse.delta_x){
+	if (sunmouse.delta_x) {
 		ev.id = LOC_X_DELTA;
 		ev.time = xtime;
 		ev.value = sunmouse.delta_x;
 		pushed += push_event (&ev);
 		sunmouse.delta_x = 0;
 	}
-	if (sunmouse.delta_y){
+	if (sunmouse.delta_y) {
 		ev.id = LOC_Y_DELTA;
 		ev.time = xtime;
 		ev.value = sunmouse.delta_y;
 		pushed += push_event (&ev);
 	}
 	
-	if(pushed != 0) {
+	if (pushed != 0) {
 		/* We just completed a transaction, wake up whoever is awaiting
 		 * this event.
 		 */
-		sunmouse.ready = 1;
 		if (sunmouse.fasync)
 			kill_fasync (sunmouse.fasync, SIGIO, POLL_IN);
 		wake_up_interruptible(&sunmouse.proc_list);
@@ -379,9 +392,9 @@
 static int
 sun_mouse_open(struct inode * inode, struct file * file)
 {
-	if(sunmouse.active++)
+	if (sunmouse.active++)
 		return 0;
-	sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
+	sunmouse.delta_x = sunmouse.delta_y = 0;
 	sunmouse.button_state = 0x80;
 	sunmouse.vuid_mode = VUID_NATIVE;
 	return 0;
@@ -401,9 +414,7 @@
 sun_mouse_close(struct inode *inode, struct file *file)
 {
 	sun_mouse_fasync (-1, file, 0);
-	if (--sunmouse.active)
-		return 0;
-	sunmouse.ready = 0;
+	sunmouse.active--;
 	return 0;
 }
 
@@ -419,49 +430,57 @@
 	       size_t count, loff_t *ppos)
 {
 	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
 
-	if (queue_empty ()){
+	if (queue_empty ()) {
 		if (file->f_flags & O_NONBLOCK)
 			return -EWOULDBLOCK;
 		add_wait_queue (&sunmouse.proc_list, &wait);
-		while (queue_empty () && !signal_pending(current)) {
-			current->state = TASK_INTERRUPTIBLE;
-			schedule ();
+repeat:
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (queue_empty() && !signal_pending(current)) {
+			schedule();
+			goto repeat;
 		}
 		current->state = TASK_RUNNING;
 		remove_wait_queue (&sunmouse.proc_list, &wait);
 	}
-	if (gen_events){
+	if (gen_events) {
 		char *p = buffer, *end = buffer+count;
 		
+		spin_lock_irqsave(&sunmouse.lock, flags);
 		while (p < end && !queue_empty ()){
+			Firm_event this_event;
+
+			get_from_queue(&this_event);
+			spin_unlock_irqrestore(&sunmouse.lock, flags);
+
 #ifdef CONFIG_SPARC32_COMPAT
 			if (current->thread.flags & SPARC_FLAG_32BIT) {
-				Firm_event *q = get_from_queue();
-				
 				if ((end - p) <
 				    ((sizeof(Firm_event) - sizeof(struct timeval) +
 				      (sizeof(u32) * 2))))
 					break;
-				copy_to_user_ret((Firm_event *)p, q, 
+				copy_to_user_ret((Firm_event *)p, &this_event,
 						 sizeof(Firm_event)-sizeof(struct timeval),
 						 -EFAULT);
 				p += sizeof(Firm_event)-sizeof(struct timeval);
-				__put_user_ret(q->time.tv_sec, (u32 *)p, -EFAULT);
+				__put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT);
 				p += sizeof(u32);
-				__put_user_ret(q->time.tv_usec, (u32 *)p, -EFAULT);
+				__put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT);
 				p += sizeof(u32);
 			} else
 #endif	
 			{	
 				if ((end - p) < sizeof(Firm_event))
 					break;
-				copy_to_user_ret((Firm_event *)p, get_from_queue(),
+				copy_to_user_ret((Firm_event *)p, &this_event,
 				     		 sizeof(Firm_event), -EFAULT);
 				p += sizeof (Firm_event);
 			}
+			spin_lock_irqsave(&sunmouse.lock, flags);
 		}
-		sunmouse.ready = !queue_empty ();
+		spin_unlock_irqrestore(&sunmouse.lock, flags);
 		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 		return p-buffer;
 	} else {
@@ -470,9 +489,24 @@
 		if (count < limit)
 			limit = count;
 		for (c = 0; c < limit; c++) {
-			put_user(sunmouse.queue.stream[sunmouse.tail], buffer);
+			unsigned char val;
+			int empty = 0;
+
+			spin_lock_irqsave(&sunmouse.lock, flags);
+			if (queue_empty()) {
+				empty = 1;
+				val = 0;
+			} else {
+				val = sunmouse.queue.stream[sunmouse.tail];
+				sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
+			}
+			spin_unlock_irqrestore(&sunmouse.lock, flags);
+
+			if (empty)
+				break;
+
+			put_user(val, buffer);
 			buffer++;
-			sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
 		}
 		while (c < count) {
 			if (c >= 5)
@@ -481,7 +515,6 @@
 			buffer++;
 			c++;
 		}
-		sunmouse.ready = !queue_empty();
 		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 		return c;
 	}
@@ -494,7 +527,7 @@
 static unsigned int sun_mouse_poll(struct file *file, poll_table *wait)
 {
 	poll_wait(file, &sunmouse.proc_list, wait);
-	if(sunmouse.ready)
+	if(!queue_empty())
 		return POLLIN | POLLRDNORM;
 	return 0;
 }
@@ -516,8 +549,11 @@
 			int value;
 
 			get_user_ret(value, (int *)arg, -EFAULT);
+
+			spin_lock_irq(&sunmouse.lock);
 			sunmouse.vuid_mode = value;
 			sunmouse.head = sunmouse.tail = 0;
+			spin_unlock_irq(&sunmouse.lock);
 		} else
 			return -EINVAL;
 		break;
@@ -556,10 +592,11 @@
 {
 	printk("Sun Mouse-Systems mouse driver version 1.00\n");
 
-	sunmouse.ready = sunmouse.active = 0;
+	sunmouse.active = 0;
 	misc_register (&sun_mouse_mouse);
 	sunmouse.delta_x = sunmouse.delta_y = 0;
 	sunmouse.button_state = 0x80;
 	init_waitqueue_head(&sunmouse.proc_list);
+	spin_lock_init(&sunmouse.lock);
 	sunmouse.byte = 69;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.3.99-pre5/linux/drivers/sbus/char/zs.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sbus/char/zs.c	Wed Apr 26 12:13:16 2000
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.56 2000/03/12 04:02:11 davem Exp $
+/* $Id: zs.c,v 1.57 2000/04/26 09:36:32 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1928,7 +1928,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.56 $";
+	char *revision = "$Revision: 1.57 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2415,7 +2415,11 @@
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
 	serial_driver.driver_name = "serial";
+#ifdef CONFIG_DEVFS_FS
 	serial_driver.name = "tts/%d";
+#else
+	serial_driver.name = "ttyS";
+#endif
 	serial_driver.major = TTY_MAJOR;
 	serial_driver.minor_start = 64;
 	serial_driver.num = NUM_CHANNELS;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.3.99-pre5/linux/drivers/scsi/53c7,8xx.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/scsi/53c7,8xx.c	Wed Apr 12 09:33:55 2000
@@ -3145,7 +3145,7 @@
     save_flags(flags);
     cli();
     for (bp = (struct NCR53c7x0_break *) host->breakpoints;
-	    bp; bp = (struct NCR53c7x0_break *) bp->next); {
+	    bp; bp = (struct NCR53c7x0_break *) bp->next) {
 	    sprintf (buf, "scsi%d : bp : success : at %08x, replaces %08x %08x",
 		bp->addr, bp->old[0], bp->old[1]);
 	    len = strlen(buf);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.3.99-pre5/linux/drivers/scsi/ChangeLog.ncr53c8xx	Tue Apr 11 15:09:18 2000
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Mon Apr 24 16:16:08 2000
@@ -1,3 +1,9 @@
+Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2i
+	- Return value 1 (instead of 0) from the driver setup routine.
+	- Let the driver also attach controllers that have been set to 
+	  OFF in the NVRAM as it did prior to revision 3.2g.
+
 Sat Apr 1  12:00 2000 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.2h
 	- Fix a compilation problem on Alpha introduced in version 3.2g.
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx
--- v2.3.99-pre5/linux/drivers/scsi/ChangeLog.sym53c8xx	Tue Apr 11 15:09:18 2000
+++ linux/drivers/scsi/ChangeLog.sym53c8xx	Mon Apr 24 16:16:13 2000
@@ -1,5 +1,11 @@
+Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5m
+	- Return value 1 (instead of 0) from the driver setup routine.
+	- Donnot enable PCI DAC cycles. This just broke support for 
+	  SYM534C896 on sparc64. Problem fixed by David S. Miller.
+
 Sat Apr 1  12:00 2000 Gerard Roudier (groudier@club-internet.fr)
-	* revision 1.5l
+	* version sym53c8xx-1.5l
 	- Tiny change for __sparc__ appeared in 2.3.99-pre4.1 that 
 	  applies to cache line size (? Probably from David S Miller).
 	- Make sure no data transfer will happen for Scsi_Cmnd requests 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c
--- v2.3.99-pre5/linux/drivers/scsi/NCR53C9x.c	Tue Nov 23 22:42:21 1999
+++ linux/drivers/scsi/NCR53C9x.c	Fri Apr 21 16:08:45 2000
@@ -3542,7 +3542,7 @@
 		esp->dma_irq_exit(esp);
 }
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
 	struct NCR_ESP *esp;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v2.3.99-pre5/linux/drivers/scsi/README.st	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/README.st	Mon Apr 24 13:54:22 2000
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Sat Mar 11 10:34:44 2000 by makisara@kai.makisara.local
+Last modified: Sat Apr 22 14:50:25 2000 by makisara@kai.makisara.local
 
 
 BASICS
@@ -115,8 +115,8 @@
 at the next tape operation.
 
 Buffered writes and asynchronous writes may in some rare cases cause
-problems in multivolume operations if there is not enough space after
-the early-warning mark to flush the driver buffer.
+problems in multivolume operations if there is not enough space on the
+tape after the early-warning mark to flush the driver buffer.
 
 Read ahead for fixed block mode (ST_READ_AHEAD). Filling the buffer is
 attempted even if the user does not want to get all of the data at
@@ -124,11 +124,11 @@
 a filemark to truncate a read request or that don't like backspacing.
 
 The buffer size is defined (in 1024 byte units) by ST_BUFFER_BLOCKS or
-at boot time. If this size is not enough, the driver tries to allocate
-a large enough temporary buffer that is released when the device is
-closed. Buffer allocation uses chunks of memory having sizes
-2^n * (page size). Because of this the actual buffer size may be
-larger than the buffer size specified with ST_BUFFER_BLOCKS.
+at boot time. If this size is not large enough, the driver tries to
+temporarily enlarge the buffer. Buffer allocation uses chunks of
+memory having sizes 2^n * (page size). Because of this the actual
+buffer size may be larger than the buffer size specified with
+ST_BUFFER_BLOCKS.
 
 A small number of buffers are allocated at driver initialisation. The
 maximum number of these buffers is defined by ST_MAX_BUFFERS. The
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.3.99-pre5/linux/drivers/scsi/ide-scsi.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/scsi/ide-scsi.c	Thu Apr 13 22:50:32 2000
@@ -547,6 +547,7 @@
 	idescsi_open,		/* open */
 	idescsi_ide_release,	/* release */
 	NULL,			/* media_change */
+	NULL,			/* revalidate */
 	NULL,			/* pre_reset */
 	NULL,			/* capacity */
 	NULL,			/* special */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.3.99-pre5/linux/drivers/scsi/megaraid.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/megaraid.c	Mon Apr 24 13:39:34 2000
@@ -2,14 +2,14 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 1998 American Megatrends Inc.
+ * Copyright 1999 American Megatrends Inc.
  *
  *              This program is free software; you can redistribute it and/or
  *              modify it under the terms of the GNU General Public License
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : 1.05
+ * Version : 1.07b
  * 
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -120,6 +120,14 @@
  *      also enables the driver to handle large amount of I/O requests for
  *      long duration of time.
  *
+ * Version 1.07
+ *    Removed the usage of uaccess.h file for kernel versions less than
+ *    2.0.36, as this file is not present in those versions.
+ *
+ * Version 1.07b
+ *    The MegaRAID 466 cards with 3.00 firmware lockup and seem to very
+ *    occasionally hang. We check such cards and report them. You can
+ *    get firmware upgrades to flash the board to 3.10 for free.
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -135,7 +143,7 @@
 #define CRLFSTR "\n"
 #define IOCTL_CMD_NEW  0x81
 
-#define MEGARAID_VERSION "v1.05 (October 27, 1999)"
+#define MEGARAID_VERSION "v107 (December 22, 1999)"
 
 
 #include <linux/version.h>
@@ -169,7 +177,9 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#if LINUX_VERSION_CODE > 0x020024
 #include <asm/uaccess.h>
+#endif
 
 #include "sd.h"
 #include "scsi.h"
@@ -523,7 +533,6 @@
   }
 
   SCpnt = pScb->SCpnt;
-  /*freeSCB(megaCfg, pScb);*/ /*delay this to the end of this func.*/
   pthru = &pScb->pthru;
   mbox = (mega_mailbox *) &pScb->mboxData;
 
@@ -638,13 +647,11 @@
 
   if ( islogical ) {
 	lun = (SCpnt->target * 8) + lun;
-#if 1
         if ( lun > FC_MAX_LOGICAL_DRIVES ){
             SCpnt->result = (DID_BAD_TARGET << 16);
             callDone (SCpnt);
             return NULL;
         }
-#endif
   }
   /*-----------------------------------------------------
    *
@@ -808,7 +815,6 @@
     return NULL;
   }
 
-
   mboxdata = (u8 *) & pScb->mboxData;
   mbox = (mega_ioctl_mbox *) & pScb->mboxData;
   mailbox = (mega_mailbox *) & pScb->mboxData;
@@ -843,6 +849,14 @@
   }
   /* else normal (nonpassthru) command */
 
+#if LINUX_VERSION_CODE > 0x020024
+/*
+ * usage of the function copy from user is used in case of data more than
+ * 4KB.  This is used only with adapters which supports more than 8 logical
+ * drives.  This feature is disabled on kernels earlier or same as 2.0.36
+ * as the uaccess.h file is not available with those kernels.
+ */
+
   if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { 
             /* use external data area for large xfers  */
      /* If cmnd[0] is set to IOCTL_CMD_NEW then *
@@ -868,6 +882,7 @@
       copy_from_user(kern_area,user_area,xfer_size);
       pScb->kern_area = kern_area;
   }
+#endif
 
   mbox->cmd = data[0];
   mbox->channel = data[1];
@@ -928,7 +943,9 @@
  *--------------------------------------------------------------------*/
 static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
 {
+#if LINUX_VERSION_CODE >= 0x20100
   IO_LOCK_T
+#endif
   mega_host_config    *megaCfg;
   u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
   u32 dword=0;
@@ -958,10 +975,6 @@
       if (dword != 0x10001234) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-//#if LINUX_VERSION_CODE >= 0x20100
-//        IO_UNLOCK;
-//#endif
-//	break;
 	return;
       }
     }
@@ -970,10 +983,6 @@
       if ((byte & VALID_INTR_BYTE) == 0) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-//#if LINUX_VERSION_CODE >= 0x20100
-//	IO_UNLOCK;
-//#endif
-//	break;
 	return;
       }
       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
@@ -1035,9 +1044,6 @@
  */
 	if (pScb->state == SCB_ABORTED) {
           SCpnt = pScb->SCpnt;
-#if DEBUG
-printk("megaraid_isr:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
-#endif
 	}
 	if (pScb->state == SCB_RESET) {
           SCpnt = pScb->SCpnt;
@@ -1135,9 +1141,6 @@
 #endif
 
   /* Wait until mailbox is free */
-#if 0
-  while (mega_busyWaitMbox (megaCfg))
-#endif
   if (mega_busyWaitMbox (megaCfg)) {
     printk("Blocked mailbox......!!\n");
     udelay(1000);
@@ -1190,7 +1193,6 @@
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
-//	mega_rundoneq (megaCfg);
       }
 
       WRINDOOR (megaCfg, phys_mbox | 0x2);
@@ -1209,7 +1211,6 @@
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
-//	mega_rundoneq (megaCfg);
       }
       else {
 	TRACE (("Error: NULL pScb!\n"));
@@ -1348,7 +1349,6 @@
   u32 paddr;
   u8 retval;
 
-
   /* Initialize adapter inquiry mailbox*/
   paddr = virt_to_bus (megaCfg->mega_buffer);
   mbox = (mega_mailbox *) mboxData;
@@ -1420,25 +1420,6 @@
     megaCfg->host->can_queue = MAX_COMMANDS-1;
   }
 
-#if 0 
-  int i;
-  printk (KERN_DEBUG "---- Logical drive info from enquiry3 struct----\n");
-  for (i = 0; i < megaCfg->numldrv; i++) {
-    printk ("%d: size: %d prop: %x state: %x\n", i,
-	    enquiry3Pnt->lDrvSize[i],
-	    enquiry3Pnt->lDrvProp[i],
-	    enquiry3Pnt->lDrvState[i]);
-  }
-
-  printk (KERN_DEBUG "---- Physical drive info ----\n");
-  for (i = 0; i < FC_MAX_PHYSICAL_DEVICES; i++) {
-    if (i && !(i % 8))
-      printk ("\n");
-    printk ("%d: %x   ", i, enquiry3Pnt->pDrvState[i]);
-  }
-  printk ("\n");
-#endif
-
 #ifdef HP			/* use HP firmware and bios version encoding */
   sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
 	   megaCfg->productInfo.FwVer[2],
@@ -1584,10 +1565,43 @@
 
     mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64));
     mega_i_query_adapter (megaCfg);
-    
+   
+    if (flag == BOARD_QUARTZ) {
+      /* Check to see if this is a Dell PERC RAID controller model 466 */
+      u16 subsysid, subsysvid;
+#if LINUX_VERSION_CODE < 0x20100
+      pcibios_read_config_word (pciBus, pciDevFun,
+				PCI_SUBSYSTEM_VENDOR_ID,
+				&subsysvid);
+      pcibios_read_config_word (pciBus, pciDevFun,
+				PCI_SUBSYSTEM_ID,
+				&subsysid);
+#else
+      pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
+      pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid);
+#endif
+      if ( (subsysid == 0x1111) && (subsysvid == 0x1111) &&
+           (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) {
+	printk(KERN_WARNING
+"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
+"megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
+"megaraid: with those firmware versions on this specific card.  In order\n"
+"megaraid: to protect your data, please upgrade your firmware to version\n"
+"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
+"megaraid: site at\n"
+"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2489\n");
+	megaraid_release (host);
+#ifdef MODULE	
+	continue;
+#else
+	while(1) schedule_timeout(1 * HZ);
+#endif	
+      }
+    }
+
     /* Initialize SCBs */
     if (mega_initSCB (megaCfg)) {
-      scsi_unregister (host);
+      megaraid_release (host);
       continue;
     }
 
@@ -1723,9 +1737,6 @@
 
   /* If driver in abort or reset.. cancel this command */
   if (megaCfg->flag & IN_ABORT) {
-#if DEBUG
-printk("mq: got a request while in abort\n");
-#endif
     SCpnt->result = (DID_ABORT << 16);
     /* Add Scsi_Command to end of completed queue */
     if( megaCfg->qCompletedH == NULL ) {
@@ -1742,9 +1753,6 @@
     return 0;
   }
   else if (megaCfg->flag & IN_RESET) {
-#if DEBUG
-printk("mq: got a request while in reset\n");
-#endif
     SCpnt->result = (DID_RESET << 16);
     /* Add Scsi_Command to end of completed queue */
     if( megaCfg->qCompletedH == NULL ) {
@@ -1777,16 +1785,9 @@
     megaCfg->qPendingT->next = NULL;
     megaCfg->qPcnt++;
 
-
-    /* Issue any pending command to the card if not in ISR */
-//    if (!(megaCfg->flag & IN_ISR)) {
       mega_runpendq(megaCfg);
-//    }
-/* 
- * try running the pend queue, irrespective of the driver's context.
- * -cn 
- */
 
+#if LINUX_VERSION_CODE > 0x020024
     if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
     {  /* user data from external user buffer */
           char *user_area;
@@ -1804,6 +1805,7 @@
 
           mega_freeSCB(megaCfg, pScb);
     }
+#endif
   }
 
   megaCfg->flag &= ~IN_QUEUE;
@@ -1858,9 +1860,6 @@
 
   megaCfg->flag |= IN_ABORT;
 
-#if DEBUG
-printk("ma:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
-#endif
   for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
     if (pScb->SCpnt == SCpnt) {
       /* Found an aborting command */
@@ -1912,20 +1911,6 @@
     }
   }
 
-#if 0
-  TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
-	  SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
-	  SCpnt->lun));
-  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
-    if (pScb->SCpnt == SCpnt) { 
-      ser_printk("** %d<%x>  %c\n", pScb->SCpnt->pid, pScb->idx+1,
-		 pScb->state == SCB_ACTIVE ? 'A' : 'I');
-#if DEBUG
-      showMbox(pScb);
-#endif
-    }
-  }
-#endif
   megaCfg->flag &= ~IN_ABORT;
 
 #if DEBUG
@@ -1943,12 +1928,11 @@
   megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
   megaCfg->qCcnt--;
 
-  SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
+  SCpnt->host_scribble = (unsigned char *) NULL ;
   /* Callback */
   callDone (SCpnt);
 }
   mega_rundoneq(megaCfg);
-
 
   return rc;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.3.99-pre5/linux/drivers/scsi/ncr53c8xx.c	Tue Apr 11 15:09:18 2000
+++ linux/drivers/scsi/ncr53c8xx.c	Mon Apr 24 16:16:13 2000
@@ -73,7 +73,7 @@
 */
 
 /*
-**	March 6 2000, version 3.2g
+**	April 24 2000, version 3.2i
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -104,7 +104,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2h"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2i"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.3.99-pre5/linux/drivers/scsi/pci2000.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/scsi/pci2000.c	Fri Apr 21 16:46:32 2000
@@ -29,8 +29,11 @@
  *	Revisions 1.12		Mar-26-1999
  *		- Fixed spinlock and PCI configuration.
  *
+ *	Revisions 1.20		Mar-27-2000
+ *		- Added support for dynamic DMA
+ *
  ****************************************************************************/
-#define PCI2000_VERSION		"1.12"
+#define PCI2000_VERSION		"1.20"
 
 #include <linux/module.h>
 
@@ -67,32 +70,37 @@
 
 typedef struct
 	{
-	ULONG		address;
-	ULONG		length;
+	unsigned int	address;
+	unsigned int	length;
 	}	SCATGATH, *PSCATGATH;
 
 typedef struct
 	{
-	Scsi_Cmnd	*SCpnt;
-	SCATGATH	 scatGath[16];
-	UCHAR		 tag;
+	Scsi_Cmnd		*SCpnt;
+	PSCATGATH		 scatGath;
+	dma_addr_t		 scatGathDma;
+	UCHAR			*cdb;
+	dma_addr_t		 cdbDma; 
+	UCHAR			 tag;
 	}	DEV2000, *PDEV2000;
 
 typedef struct
 	{
-	USHORT		 basePort;
-	USHORT		 mb0;
-	USHORT		 mb1;
-	USHORT		 mb2;
-	USHORT		 mb3;
-	USHORT		 mb4;
-	USHORT		 cmd;
-	USHORT		 tag;
-	ULONG		 irqOwned;
-	DEV2000	 	 dev[MAX_BUS][MAX_UNITS];
+	ULONG			 basePort;
+	ULONG			 mb0;
+	ULONG			 mb1;
+	ULONG			 mb2;
+	ULONG			 mb3;
+	ULONG			 mb4;
+	ULONG			 cmd;
+	ULONG			 tag;
+	ULONG			 irqOwned;
+	struct pci_dev	*pdev;
+	DEV2000	 		 dev[MAX_BUS][MAX_UNITS];
 	}	ADAPTER2000, *PADAPTER2000;
 
 #define HOSTDATA(host) ((PADAPTER2000)&host->hostdata)
+#define consistentLen (MAX_BUS * MAX_UNITS * (16 * sizeof (SCATGATH) + MAX_COMMAND_SIZE))
 
 
 static struct	Scsi_Host 	   *PsiHost[MAXADAPTER] = {NULL,};  // One for each adapter
@@ -193,20 +201,31 @@
  ****************************************************************/
 static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev)
 	{
-	int	z;
+	int					 z;
+	int					 zc;
+	struct scatterlist	*sg;
 
 	if ( SCpnt->use_sg )
 		{
-		for ( z = 0;  z < SCpnt->use_sg;  z++ )
+		sg = (struct scatterlist *)SCpnt->request_buffer;
+		zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+		for ( z = 0;  z < zc;  z++ )
 			{
-			pdev->scatGath[z].address = virt_to_bus (((struct scatterlist *)SCpnt->request_buffer)[z].address);
-			pdev->scatGath[z].length = ((struct scatterlist *)SCpnt->request_buffer)[z].length;
+			pdev->scatGath[z].address = cpu_to_le32 (sg_dma_address (sg));
+			pdev->scatGath[z].length = cpu_to_le32 (sg_dma_len (sg++));
 			}
-		outl (virt_to_bus (pdev->scatGath), padapter->mb2);
-		outl ((SCpnt->use_sg << 24) | SCpnt->request_bufflen, padapter->mb3);
+		outl (pdev->scatGathDma, padapter->mb2);
+		outl ((zc << 24) | SCpnt->request_bufflen, padapter->mb3);
 		return FALSE;
 		}
-	outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
+	if ( !SCpnt->request_bufflen)
+		{
+		outl (0, padapter->mb2);
+		outl (0, padapter->mb3);
+		return TRUE;
+		}
+	SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+	outl (SCpnt->SCp.have_data_in, padapter->mb2);
 	outl (SCpnt->request_bufflen, padapter->mb3);
 	return TRUE;
 	}
@@ -254,23 +273,13 @@
 	int					pun;
 	int					bus;
 	int					z;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    int					flags;
-#else /* version >= v2.1.95 */
     unsigned long		flags;
-#endif /* version >= v2.1.95 */
 
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /* Disable interrupts, if they aren't already disabled. */
-    save_flags (flags);
-    cli ();
-#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 
 	DEB(printk ("\npci2000 recieved interrupt "));
 	for ( z = 0; z < NumAdapters;  z++ )										// scan for interrupt to process
@@ -306,14 +315,39 @@
 				{
 				pdev->tag = 0;
 				SCpnt = pdev->SCpnt;
-				goto irqProceed;
+				goto unmapProceed;
     			}
 			}
     	}
 
 	outb_p (0xFF, padapter->tag);												// clear the op interrupt
 	outb_p (CMD_DONE, padapter->cmd);											// complete the op
-	goto irq_return;;																		// done, but, with what?
+	goto irq_return;;															// done, but, with what?
+
+unmapProceed:;
+	if ( !bus )
+		{
+		switch ( SCpnt->cmnd[0] )
+			{
+			case SCSIOP_TEST_UNIT_READY:
+				pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE);
+				goto irqProceed;
+			case SCSIOP_READ_CAPACITY:
+				pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, 8, PCI_DMA_FROMDEVICE);
+				goto irqProceed;
+			case SCSIOP_VERIFY:
+			case SCSIOP_START_STOP_UNIT:
+			case SCSIOP_MEDIUM_REMOVAL:
+				goto irqProceed;
+			}
+		}
+	if ( SCpnt->SCp.have_data_in )
+		pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	else 
+		{
+		if ( SCpnt->use_sg )
+			pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		}
 
 irqProceed:;
 	if ( tag & ERR08_TAGGED )												// is there an error here?
@@ -359,20 +393,12 @@
 	OpDone (SCpnt, DID_OK << 16);
 
 irq_return:;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /*
-     * Restore the original flags which will enable interrupts
-     * if and only if they were enabled on entry.
-     */
-    restore_flags (flags);
-#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:	Pci2000_QueueCommand
@@ -403,6 +429,7 @@
 		}
 
 	SCpnt->scsi_done = done;
+	SCpnt->SCp.have_data_in = 0;
 	pdev->SCpnt = SCpnt;  									// Save this command data
 
 	if ( WaitReady (padapter) )
@@ -428,7 +455,9 @@
 
 		outw_p (pun | (lun << 8), padapter->mb0);
 		outw_p (SCpnt->cmd_len << 8, padapter->mb0 + 2);
-		outl (virt_to_bus (cdb), padapter->mb1);
+		memcpy (pdev->cdb, cdb, MAX_COMMAND_SIZE);
+
+		outl (pdev->cdbDma, padapter->mb1);
 		if ( BuildSgList (SCpnt, padapter, pdev) )
 			cmd = CMD_SCSI_THRU;
 		else
@@ -469,7 +498,11 @@
 							goto finished;
 							}
 						else
-							outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
+							{
+							SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen,
+													  scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+							outl (SCpnt->SCp.have_data_in, padapter->mb2);
+							}
 						outl (cdb[5], padapter->mb0);
 						outl (cdb[3], padapter->mb3);
 						cmd = CMD_DASD_RAID_RQ;
@@ -480,31 +513,35 @@
 			
 			if ( SCpnt->use_sg )
 				{
-				outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2);
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, ((struct scatterlist *)SCpnt->request_buffer)->address, 
+										  SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
 				}
 			else
 				{
-				outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, 
+										  SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
 				}
+			outl (SCpnt->SCp.have_data_in, padapter->mb2);
 			outl (SCpnt->request_bufflen, padapter->mb3);
 			cmd = CMD_DASD_SCSI_INQ;
 			break;
 
 		case SCSIOP_TEST_UNIT_READY:			// test unit ready CDB
-			outl (virt_to_bus (SCpnt->sense_buffer), padapter->mb2);
+			SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->sense_buffer, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE);
+			outl (SCpnt->SCp.have_data_in, padapter->mb2);
 			outl (sizeof (SCpnt->sense_buffer), padapter->mb3);
 			cmd = CMD_TEST_READY;
 			break;
 
-		case SCSIOP_READ_CAPACITY:			  	// read capctiy CDB
+		case SCSIOP_READ_CAPACITY:			  	// read capacity CDB
 			if ( SCpnt->use_sg )
 				{
-				outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2);
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, ((struct scatterlist *)(SCpnt->request_buffer))->address,
+										  8, PCI_DMA_FROMDEVICE);
 				}
 			else
-				{
-				outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2);
-				}
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, 8, PCI_DMA_FROMDEVICE);
+			outl (SCpnt->SCp.have_data_in, padapter->mb2);
 			outl (8, padapter->mb3);
 			cmd = CMD_DASD_CAP;
 			break;
@@ -629,37 +666,23 @@
 	PADAPTER2000	    padapter;
 	int					z, zz;
 	int					setirq;
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	struct pci_dev	   *pdev = NULL;
-#else
-	UCHAR	pci_bus, pci_device_fn;
-#endif
+	UCHAR			   *consistent;
+	dma_addr_t			consistentDma;
+
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	if ( !pci_present () )
-#else
-	if ( !pcibios_present () )
-#endif
 		{
 		printk ("pci2000: PCI BIOS not present\n");
 		return 0;
 		}
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL )
-#else
-	while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) )
-#endif
 		{
 		pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
 		padapter = HOSTDATA(pshost);
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
-		padapter->basePort = pci_resource_start (pdev, 1);
-#else
-		pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
-		padapter->basePort &= 0xFFFE;
-#endif
+		padapter->basePort = pdev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
 		DEB (printk ("\nBase Regs = %#04X", padapter->basePort));			// get the base I/O port address
 		padapter->mb0	= padapter->basePort + RTR_MAILBOX;		   			// get the 32 bit mail boxes
 		padapter->mb1	= padapter->basePort + RTR_MAILBOX + 4;
@@ -668,6 +691,7 @@
 		padapter->mb4	= padapter->basePort + RTR_MAILBOX + 16;
 		padapter->cmd	= padapter->basePort + RTR_LOCAL_DOORBELL;			// command register
 		padapter->tag	= padapter->basePort + RTR_PCI_DOORBELL;			// tag/response register
+		padapter->pdev = pdev;
 
 		if ( WaitReady (padapter) )
 			goto unregister;
@@ -676,11 +700,14 @@
 		if ( WaitReady (padapter) )
 			goto unregister;
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+		consistent = pci_alloc_consistent (pdev, consistentLen, &consistentDma);
+		if ( !consistent )
+			{
+			printk ("Unable to allocate DMA memory for PCI-2000 controller.\n");
+			goto unregister;
+			}
+		
 		pshost->irq = pdev->irq;
-#else
-		pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
-#endif
 		setirq = 1;
 		padapter->irqOwned = 0;
 		for ( z = 0;  z < installed;  z++ )									// scan for shared interrupts
@@ -695,6 +722,7 @@
 				if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2000", padapter) < 0 )
 					{
 					printk ("Unable to allocate IRQ for PCI-2000 controller.\n");
+					pci_free_consistent (pdev, consistentLen, consistent, consistentDma);
 					goto unregister;
 					}
 				}
@@ -710,9 +738,19 @@
 
 		for ( zz = 0;  zz < MAX_BUS;  zz++ )
 			for ( z = 0; z < MAX_UNITS;  z++ )
+				{
 				padapter->dev[zz][z].tag = 0;
+				padapter->dev[zz][z].scatGath = (PSCATGATH)consistent;
+				padapter->dev[zz][z].scatGathDma = consistentDma;
+				consistent += 16 * sizeof (SCATGATH);
+				consistentDma += 16 * sizeof (SCATGATH);
+				padapter->dev[zz][z].cdb = (UCHAR *)consistent;
+				padapter->dev[zz][z].cdbDma = consistentDma;
+				consistent += MAX_COMMAND_SIZE;
+				consistentDma += MAX_COMMAND_SIZE;
+				}
 			
-		printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %X  IRQ = %d\n", padapter->basePort, pshost->irq);
+		printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %lX  IRQ = %d\n", padapter->basePort, pshost->irq);
 		printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION,  __DATE__, __TIME__);
 		found++;
 		if ( ++installed < MAXADAPTER )
@@ -774,12 +812,9 @@
     PADAPTER2000	padapter = HOSTDATA (pshost);
 
 	if ( padapter->irqOwned )
-#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
-	    free_irq (pshost->irq);
-#else /* version >= v1.3.70 */
 		free_irq (pshost->irq, padapter);
-#endif /* version >= v1.3.70 */
-    release_region (pshost->io_port, pshost->n_io_port);
+	pci_free_consistent (padapter->pdev, consistentLen, padapter->dev[0][0].scatGath, padapter->dev[0][0].scatGathDma);
+	release_region (pshost->io_port, pshost->n_io_port);
     scsi_unregister(pshost);
     return 0;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.3.99-pre5/linux/drivers/scsi/pci2220i.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/scsi/pci2220i.c	Fri Apr 21 16:46:32 2000
@@ -29,6 +29,9 @@
  *		- Added code for ATAPI devices.
  *		- Double buffer for scatter/gather support
  *
+ *	Revision 2.10		March-27-2000
+ *		- Added support for dynamic DMA
+ *
  ****************************************************************************/
 
 //#define DEBUG 1
@@ -57,7 +60,7 @@
 #include "psi_dale.h"
 
 
-#define	PCI2220I_VERSION		"2.00"
+#define	PCI2220I_VERSION		"2.10"
 #define	READ_CMD				IDE_CMD_READ_MULTIPLE
 #define	WRITE_CMD				IDE_CMD_WRITE_MULTIPLE
 #define	MAX_BUS_MASTER_BLOCKS	SECTORSXFER		// This is the maximum we can bus master
@@ -99,32 +102,33 @@
 	{
 	USHORT		 bigD;					// identity is a PCI-2240I if true, otherwise a PCI-2220I
 	USHORT		 atapi;					// this interface is for ATAPI devices only
-	USHORT		 regDmaDesc;			// address of the DMA discriptor register for direction of transfer
-	USHORT		 regDmaCmdStat;			// Byte #1 of DMA command status register
-	USHORT		 regDmaAddrPci;			// 32 bit register for PCI address of DMA
-	USHORT		 regDmaAddrLoc;			// 32 bit register for local bus address of DMA
-	USHORT		 regDmaCount;			// 32 bit register for DMA transfer count
-	USHORT		 regDmaMode;			// 32 bit register for DMA mode control
-	USHORT		 regRemap;				// 32 bit local space remap
-	USHORT		 regDesc;				// 32 bit local region descriptor
-	USHORT		 regRange;				// 32 bit local range
-	USHORT		 regIrqControl;			// 16 bit Interrupt enable/disable and status
-	USHORT		 regScratchPad;			// scratch pad I/O base address
-	USHORT		 regBase;				// Base I/O register for data space
-	USHORT		 regData;				// data register I/O address
-	USHORT		 regError;				// error register I/O address
-	USHORT		 regSectCount;			// sector count register I/O address
-	USHORT		 regLba0;				// least significant byte of LBA
-	USHORT		 regLba8;				// next least significant byte of LBA
-	USHORT		 regLba16;				// next most significan byte of LBA
-	USHORT		 regLba24;				// head and most 4 significant bits of LBA
-	USHORT		 regStatCmd;			// status on read and command on write register
-	USHORT		 regStatSel;			// board status on read and spigot select on write register
-	USHORT		 regFail;				// fail bits control register
-	USHORT		 regAltStat;			// alternate status and drive control register
-	USHORT		 basePort;				// PLX base I/O port
+	ULONG		 regDmaDesc;			// address of the DMA discriptor register for direction of transfer
+	ULONG		 regDmaCmdStat;			// Byte #1 of DMA command status register
+	ULONG		 regDmaAddrPci;			// 32 bit register for PCI address of DMA
+	ULONG		 regDmaAddrLoc;			// 32 bit register for local bus address of DMA
+	ULONG		 regDmaCount;			// 32 bit register for DMA transfer count
+	ULONG		 regDmaMode;			// 32 bit register for DMA mode control
+	ULONG		 regRemap;				// 32 bit local space remap
+	ULONG		 regDesc;				// 32 bit local region descriptor
+	ULONG		 regRange;				// 32 bit local range
+	ULONG		 regIrqControl;			// 16 bit Interrupt enable/disable and status
+	ULONG		 regScratchPad;			// scratch pad I/O base address
+	ULONG		 regBase;				// Base I/O register for data space
+	ULONG		 regData;				// data register I/O address
+	ULONG		 regError;				// error register I/O address
+	ULONG		 regSectCount;			// sector count register I/O address
+	ULONG		 regLba0;				// least significant byte of LBA
+	ULONG		 regLba8;				// next least significant byte of LBA
+	ULONG		 regLba16;				// next most significan byte of LBA
+	ULONG		 regLba24;				// head and most 4 significant bits of LBA
+	ULONG		 regStatCmd;			// status on read and command on write register
+	ULONG		 regStatSel;			// board status on read and spigot select on write register
+	ULONG		 regFail;				// fail bits control register
+	ULONG		 regAltStat;			// alternate status and drive control register
+	ULONG		 basePort;				// PLX base I/O port
 	USHORT		 timingMode;			// timing mode currently set for adapter
 	USHORT		 timingPIO;				// TRUE if PIO timing is active
+	struct pci_dev	*pcidev;
 	ULONG		 timingAddress;			// address to use on adapter for current timing mode
 	ULONG		 irqOwned;				// owned IRQ or zero if shared
 	UCHAR		 numberOfDrives;		// saved number of drives on this controller
@@ -151,6 +155,7 @@
 	struct timer_list	reconTimer;	
 	struct timer_list	timer;
 	UCHAR		*kBuffer;
+	dma_addr_t	 kBufferDma;
 	UCHAR		 reqSense;
 	UCHAR		 atapiCdb[16];
 	UCHAR		 atapiSpecial;
@@ -520,7 +525,7 @@
 		}
 	
 	outl (padapter->timingAddress, padapter->regDmaAddrLoc);
-	outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+	outl (padapter->kBufferDma, padapter->regDmaAddrPci);
 	outl (zl, padapter->regDmaCount);
 	outb_p (0x03, padapter->regDmaCmdStat);							// kick the DMA engine in gear
 	}
@@ -539,7 +544,7 @@
 static void AtapiBusMaster (PADAPTER2220I padapter, UCHAR datain, ULONG length)
 	{
 	outl (padapter->timingAddress, padapter->regDmaAddrLoc);
-	outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+	outl (padapter->kBufferDma, padapter->regDmaAddrPci);
 	outl (length, padapter->regDmaCount);
 	if ( datain )
 		{
@@ -1017,10 +1022,6 @@
 	UCHAR			error;
 
 	padapter->expectingIRQ = 0;
-#ifdef DEBUG
-	printk (" @@@@@@  status: %X @@@@@@@ ", status);
-	STOP_HERE();	
-#endif
 	if ( status & IDE_STATUS_WRITE_FAULT )
 		{
 		return DID_PARITY << 16;
@@ -1154,23 +1155,13 @@
 	POUR_DEVICE		pdev = padapter->pdev;
 	UCHAR			status = IDE_STATUS_BUSY;
 	UCHAR			temp, temp1;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    int					flags;
-#else /* version >= v2.1.95 */
     unsigned long		flags;
-#endif /* version >= v2.1.95 */
 
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /* Disable interrupts, if they aren't already disabled. */
-    save_flags (flags);
-    cli ();
-#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 	DEB (printk ("\nPCI2220I: Timeout expired "));
 
 	if ( padapter->failinprog )
@@ -1299,20 +1290,12 @@
 	OpDone (padapter, DecodeError (padapter, status));
 
 timerExpiryDone:;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /*
-     * Restore the original flags which will enable interrupts
-     * if and only if they were enabled on entry.
-     */
-    restore_flags (flags);
-#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:			SetReconstruct	:LOCAL
@@ -1353,23 +1336,13 @@
 	ULONG			zl;
 	UCHAR			zc;
 	USHORT			z;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    int				flags;
-#else /* version >= v2.1.95 */
     unsigned long	flags;
-#endif /* version >= v2.1.95 */
 
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /* Disable interrupts, if they aren't already disabled. */
-    save_flags (flags);
-    cli ();
-#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 
 	padapter = (PADAPTER2220I)data;
 	if ( padapter->SCpnt )
@@ -1589,20 +1562,12 @@
 	padapter->reconPhase = RECON_PHASE_LAST;
 
 reconTimerExpiry:;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /*
-     * Restore the original flags which will enable interrupts
-     * if and only if they were enabled on entry.
-     */
-    restore_flags (flags);
-#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:	Irq_Handler	:LOCAL
@@ -1629,23 +1594,13 @@
 	ATAPI_ERROR			errora;
 	int					z;
 	ULONG				zl;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    int					flags;
-#else /* version >= v2.1.95 */
     unsigned long		flags;
-#endif /* version >= v2.1.95 */
 
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /* Disable interrupts, if they aren't already disabled. */
-    save_flags (flags);
-    cli ();
-#else /* version >= v2.1.95 */
     /*
      * Disable interrupts, if they aren't already disabled and acquire
      * the I/O spinlock.
      */
     spin_lock_irqsave (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 
 //	DEB (printk ("\npci2220i recieved interrupt\n"));
 
@@ -1833,7 +1788,7 @@
 						}
 					else
 						outl (padapter->timingAddress, padapter->regDmaAddrLoc);
-					outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+					outl (padapter->kBufferDma, padapter->regDmaAddrPci);
 					outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount);
 					outb_p (8, padapter->regDmaDesc);						// read operation
 					if ( padapter->bigD )
@@ -2069,20 +2024,12 @@
 
 	OpDone (padapter, zl);
 irq_return:;
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
-    /*
-     * Restore the original flags which will enable interrupts
-     * if and only if they were enabled on entry.
-     */
-    restore_flags (flags);
-#else /* version >= v2.1.95 */
     /*
      * Release the I/O spinlock and restore the original flags
      * which will enable interrupts if and only if they were
      * enabled on entry.
      */
     spin_unlock_irqrestore (&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
 	}
 /****************************************************************
  *	Name:	Pci2220i_QueueCommand
@@ -2421,30 +2368,26 @@
  *	Parameters:		pshost		  - Pointer to SCSI host data structure.
  *					bigd		  - PCI-2240I identifier
  *					pcidev		  - Pointer to device data structure.
- *					pci_bus		  - PCI bus number.
- *					pci_device_fn - PCI device and function number.
  *
  *	Returns:		TRUE if failure to install.
  *
  ****************************************************************/
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcidev)
-#else
-static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, UCHAR pci_bus, UCHAR pci_device_fn)
-#endif
 	{
 	PADAPTER2220I	padapter;
 	int				setirq;
 	int				z;
 	USHORT			zr, zl;
+	UCHAR		   *consistent;
+	dma_addr_t		consistentDma;
 
 	padapter = HOSTDATA(pshost);
 	memset (padapter, 0, sizeof (ADAPTER2220I));
 	memset (&DaleSetup, 0, sizeof (DaleSetup));
 	memset (DiskMirror, 0, sizeof (DiskMirror));
 
-	zr = pci_resource_start (pcidev, 1);
-	zl = pci_resource_start (pcidev, 2);
+	zr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+	zl = pcidev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
 
 	padapter->basePort = zr;
 	padapter->regRemap		= zr + RTR_LOCAL_REMAP;					// 32 bit local space remap
@@ -2465,6 +2408,7 @@
 	padapter->regStatSel	= zl + REG_STAT_SEL;					// board status on read and spigot select on write register
 	padapter->regFail		= zl + REG_FAIL;
 	padapter->regAltStat	= zl + REG_ALT_STAT;
+	padapter->pcidev		= pcidev;
 
 	if ( bigd )
 		{
@@ -2490,11 +2434,7 @@
 	if ( !bigd && !padapter->numberOfDrives )						// if no devices on this board
 		return TRUE;
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	pshost->irq = pcidev->irq;
-#else
-	pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
-#endif
 	setirq = 1;
 	for ( z = 0;  z < Installed;  z++ )								// scan for shared interrupts
 		{
@@ -2513,23 +2453,21 @@
 			}
 		padapter->irqOwned = pshost->irq;							// set IRQ as owned
 		}
+
 	if ( padapter->numberOfDrives )
-		padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC);
+		consistent = pci_alloc_consistent (pcidev, SECTORSXFER * BYTES_PER_SECTOR, &consistentDma);
 	else
-		padapter->kBuffer = kmalloc (ATAPI_TRANSFER, GFP_DMA | GFP_ATOMIC);
-	if ( !padapter->kBuffer )
+		consistent = pci_alloc_consistent (pcidev, ATAPI_TRANSFER, &consistentDma);
+	if ( !consistent )
 		{
 		printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
-#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
-		free_irq (pshost->irq);
-#else /* version >= v1.3.70 */
 		free_irq (pshost->irq, padapter);
-#endif /* version >= v1.3.70 */
 		return TRUE;
 		}
+	padapter->kBuffer = consistent;
+	padapter->kBufferDma = consistentDma;
 
 	PsiHost[Installed]	= pshost;									// save SCSI_HOST pointer
-
 	pshost->io_port		= padapter->basePort;
 	pshost->n_io_port	= 0xFF;
 	pshost->unique_id	= padapter->regBase;
@@ -2571,7 +2509,7 @@
 	init_timer (&padapter->reconTimer);
 	padapter->reconTimer.function = ReconTimerExpiry;
 	padapter->reconTimer.data = (unsigned long)padapter;
-	printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %X/%X  IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq);
+	printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %lX/%lX  IRQ = %ld\n", str, padapter->basePort, padapter->regBase, irq);
 	printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
 	}	
 /****************************************************************
@@ -2594,38 +2532,20 @@
 	USHORT				raidon;
 	UCHAR				spigot1, spigot2;
 	UCHAR				device;
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	struct pci_dev	   *pcidev = NULL;
-#else
-	int					found;
-	UCHAR				pci_bus, pci_device_fn;
-#endif
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	if ( !pci_present () )
-#else
-	if ( !pcibios_present () )
-#endif
 		{
 		printk ("pci2220i: PCI BIOS not present\n");
 		return 0;
 		}
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL )
-#else
-	found = 0;
-	while ( !pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, found++, &pci_bus, &pci_device_fn) )
-#endif
 		{
 		pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
 		padapter = HOSTDATA(pshost);
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 		if ( GetRegs (pshost, FALSE, pcidev) )
-#else
-		if ( GetRegs (pshost, FALSE, pci_bus, pci_device_fn) )
-#endif
 			goto unregister;
 
 		pshost->max_id = padapter->numberOfDrives;
@@ -2720,21 +2640,12 @@
 		scsi_unregister (pshost);
 		}
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 	while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_BIGD_1, pcidev)) != NULL )
-#else
-	found = 0;
-	while ( !pcibios_find_device (VENDOR_PSI, DEVICE_BIGD_1, found++, &pci_bus, &pci_device_fn) )
-#endif
 		{
 		pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
 		padapter = HOSTDATA(pshost);
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
 		if ( GetRegs (pshost, TRUE, pcidev) )
-#else
-		if ( GetRegs (pshost, TRUE, pci_bus, pci_device_fn) )
-#endif
 			goto unregister1;
 
 		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
@@ -2966,13 +2877,12 @@
 		}
 
 	if ( padapter->irqOwned )
-#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
-		free_irq (pshost->irq);
-#else /* version >= v1.3.70 */
 		free_irq (pshost->irq, padapter);
-#endif /* version >= v1.3.70 */
     release_region (pshost->io_port, pshost->n_io_port);
-	kfree (padapter->kBuffer);
+	if ( padapter->numberOfDrives )
+		pci_free_consistent (padapter->pcidev, SECTORSXFER * BYTES_PER_SECTOR, padapter->kBuffer, padapter->kBufferDma);
+	else	
+		pci_free_consistent (padapter->pcidev, ATAPI_TRANSFER, padapter->kBuffer, padapter->kBufferDma);
     scsi_unregister(pshost);
     return 0;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.3.99-pre5/linux/drivers/scsi/scsi.c	Tue Apr 11 15:09:18 2000
+++ linux/drivers/scsi/scsi.c	Mon Apr 24 18:59:07 2000
@@ -478,6 +478,7 @@
 
         SCpnt->result = 0;
 	SCpnt->underflow = 0;	/* Do not flag underflow conditions */
+	SCpnt->old_underflow = 0;
 	SCpnt->resid = 0;
 	SCpnt->state = SCSI_STATE_INITIALIZING;
 	SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
@@ -906,6 +907,7 @@
 		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	SCpnt->old_cmd_len = SCpnt->cmd_len;
 	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
+	SCpnt->old_underflow = SCpnt->underflow;
 
 	/* Start the timer ticking.  */
 
@@ -1011,6 +1013,7 @@
 		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	SCpnt->old_cmd_len = SCpnt->cmd_len;
 	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
+	SCpnt->old_underflow = SCpnt->underflow;
 
 	/* Start the timer ticking.  */
 
@@ -1271,6 +1274,7 @@
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
 	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+	SCpnt->underflow = SCpnt->old_underflow;
 
         /*
          * Zero the sense information from the last time we tried
@@ -1435,6 +1439,7 @@
 		SCpnt->old_use_sg = 0;
 		SCpnt->old_cmd_len = 0;
 		SCpnt->underflow = 0;
+		SCpnt->old_underflow = 0;
 		SCpnt->transfersize = 0;
 		SCpnt->resid = 0;
 		SCpnt->serial_number = 0;
@@ -1895,7 +1900,12 @@
 }
 #endif
 
-#ifdef CONFIG_MODULES		/* a big #ifdef block... */
+/*
+ * Some host adapters that are plugging into other subsystems register
+ * their hosts through the modules entrypoints, and don't use the big
+ * list in hosts.c.
+ */
+#if defined(CONFIG_MODULES) || defined(CONFIG_BLK_DEV_IDESCSI) || defined(CONFIG_USB_STORAGE)	/* a big #ifdef block... */
 
 /*
  * This entry point should be called by a loadable module if it is trying
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.3.99-pre5/linux/drivers/scsi/scsi.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/scsi.h	Wed Apr 26 15:30:44 2000
@@ -105,7 +105,7 @@
  */
 #define ASSERT_LOCK(_LOCK, _COUNT)
 
-#if defined(__SMP__) && defined(CONFIG_USER_DEBUG)
+#if defined(CONFIG_SMP) && defined(CONFIG_USER_DEBUG)
 #undef ASSERT_LOCK
 #define ASSERT_LOCK(_LOCK,_COUNT)       \
         { if( (_LOCK)->lock != _COUNT )   \
@@ -756,6 +756,8 @@
 
 	unsigned underflow;	/* Return error if less than
 				   this amount is transfered */
+	unsigned old_underflow;	/* save underflow here when reusing the
+				 * command for error handling */
 
 	unsigned transfersize;	/* How much we are guaranteed to
 				   transfer with each SCSI transfer
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.3.99-pre5/linux/drivers/scsi/scsi_error.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/scsi/scsi_error.c	Wed Apr 12 09:47:26 2000
@@ -409,6 +409,7 @@
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
 	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+	SCpnt->underflow = SCpnt->old_underflow;
 
 	scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
 
@@ -466,6 +467,7 @@
 	SCpnt->use_sg = 0;
 	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	SCpnt->sc_data_direction = SCSI_DATA_READ;
+	SCpnt->underflow = 0;
 
 	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
 
@@ -489,6 +491,7 @@
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
 	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+	SCpnt->underflow = SCpnt->old_underflow;
 
 	/*
 	 * Hey, we are done.  Let's look to see what happened.
@@ -533,9 +536,11 @@
 	SCpnt->request_bufflen = 256;
 	SCpnt->use_sg = 0;
 	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+	SCpnt->underflow = 0;
 	SCpnt->sc_data_direction = SCSI_DATA_NONE;
 
+	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+
 	/* Last chance to have valid sense data */
 	if (!scsi_sense_valid(SCpnt))
 		memcpy((void *) SCpnt->sense_buffer,
@@ -556,6 +561,7 @@
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->cmd_len = SCpnt->old_cmd_len;
 	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+	SCpnt->underflow = SCpnt->old_underflow;
 
 	/*
 	 * Hey, we are done.  Let's look to see what happened.
@@ -736,6 +742,7 @@
 	 */
 	SCpnt->use_sg = SCpnt->old_use_sg;
 	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+	SCpnt->underflow = SCpnt->old_underflow;
 	*SClist = SCpnt;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- v2.3.99-pre5/linux/drivers/scsi/scsi_lib.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/scsi_lib.c	Wed Apr 12 09:47:26 2000
@@ -232,6 +232,7 @@
 	SCpnt->old_use_sg = SCpnt->use_sg;
 	SCpnt->old_cmd_len = SCpnt->cmd_len;
 	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
+	SCpnt->old_underflow = SCpnt->underflow;
 	memcpy((void *) SCpnt->data_cmnd,
 	       (const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
 	SCpnt->buffer = SCpnt->request_buffer;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- v2.3.99-pre5/linux/drivers/scsi/scsi_merge.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/scsi_merge.c	Mon Apr 24 18:59:07 2000
@@ -282,7 +282,7 @@
  *		This can come up if you get a MEDIUM_ERROR, for example,
  *		as we will have "completed" all of the sectors up to and
  *		including the bad sector, and the leftover bit is what
- *		we have to do now.  This tends to be a rare occurence, so
+ *		we have to do now.  This tends to be a rare occurrence, so
  *		we aren't busting our butts to instantiate separate versions
  *		of this function for the 4 different flag values.  We
  *		probably should, however.
@@ -320,7 +320,7 @@
 	 * scsi.c allocates for this purpose
 	 * min(64,sg_tablesize) entries.
 	 */
-	if (req->nr_segments >= max_segments &&
+	if (req->nr_segments >= max_segments ||
 	    req->nr_segments >= SHpnt->sg_tablesize)
 		return 0;
 	req->nr_segments++;
@@ -339,8 +339,7 @@
 	 * check if things fit into sg_tablesize.
 	 */
 	if (req->nr_hw_segments >= SHpnt->sg_tablesize ||
-	    (req->nr_segments >= max_segments &&
-	     req->nr_segments >= SHpnt->sg_tablesize))
+	     req->nr_segments >= SHpnt->sg_tablesize)
 		return 0;
 	if (req->nr_segments >= max_segments)
 		return 0;
@@ -609,7 +608,7 @@
 	/* If it would not fit into prepared memory space for sg chain,
 	 * then don't allow the merge.
 	 */
-	if (req->nr_segments + next->nr_segments - 1 > max_segments &&
+	if (req->nr_segments + next->nr_segments - 1 > max_segments ||
 	    req->nr_segments + next->nr_segments - 1 > SHpnt->sg_tablesize) {
 		return 0;
 	}
@@ -674,7 +673,7 @@
 	}
       dont_combine:
 #ifdef DMA_CHUNK_SIZE
-	if (req->nr_segments + next->nr_segments > max_segments &&
+	if (req->nr_segments + next->nr_segments > max_segments ||
 	    req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
 		return 0;
 	}
@@ -697,7 +696,7 @@
 	 * Make sure we can fix something that is the sum of the two.
 	 * A slightly stricter test than we had above.
 	 */
-	if (req->nr_segments + next->nr_segments > max_segments &&
+	if (req->nr_segments + next->nr_segments > max_segments ||
 	    req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
 		return 0;
 	} else {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c
--- v2.3.99-pre5/linux/drivers/scsi/scsi_obsolete.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/scsi/scsi_obsolete.c	Wed Apr 12 09:47:26 2000
@@ -377,6 +377,7 @@
 		SCpnt->use_sg = SCpnt->old_use_sg;
 		SCpnt->cmd_len = SCpnt->old_cmd_len;
 		SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+		SCpnt->underflow = SCpnt->old_underflow;
 	}
 	switch (host_byte(result)) {
 	case DID_OK:
@@ -637,6 +638,7 @@
 			SCpnt->use_sg = SCpnt->old_use_sg;
 			SCpnt->cmd_len = SCpnt->old_cmd_len;
 			SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+			SCpnt->underflow = SCpnt->old_underflow;
 			SCpnt->result = 0;
                         /*
                          * Ugly, ugly.  The newer interfaces all
@@ -664,6 +666,7 @@
 		SCpnt->use_sg = SCpnt->old_use_sg;
 		SCpnt->cmd_len = SCpnt->old_cmd_len;
 		SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+		SCpnt->underflow = SCpnt->old_underflow;
                 /*
                  * The upper layers assume the lock isn't held.  We mustn't
                  * disappoint them.  When the new error handling code is in
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.99-pre5/linux/drivers/scsi/sd.c	Tue Apr 11 15:09:18 2000
+++ linux/drivers/scsi/sd.c	Thu Apr 13 22:54:26 2000
@@ -166,6 +166,37 @@
 				return -EFAULT;
 			return 0;
 		}
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+
+			if(!loc)
+				return -EINVAL;
+
+			host = rscsi_disks[DEVICE_NR(dev)].device->host;
+
+			/* default to most commonly used values */
+
+			diskinfo[0] = 0x40;
+			diskinfo[1] = 0x20;
+			diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;
+
+			/* override with calculated, extended default, or driver values */
+
+			if(host->hostt->bios_param != NULL)
+				host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],
+					    dev,
+					    &diskinfo[0]);
+			else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],
+					dev, &diskinfo[0]);
+
+			if (put_user(diskinfo[0], &loc->heads) ||
+				put_user(diskinfo[1], &loc->sectors) ||
+				put_user(diskinfo[2], (unsigned int *) &loc->cylinders) ||
+				put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start))
+				return -EFAULT;
+			return 0;
+		}
 		case BLKGETSIZE:   /* Return device size */
 			if (!arg)
 				return -EINVAL;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.99-pre5/linux/drivers/scsi/st.c	Mon Mar 27 08:08:27 2000
+++ linux/drivers/scsi/st.c	Mon Apr 24 13:54:22 2000
@@ -12,7 +12,7 @@
    Copyright 1992 - 2000 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Sun Mar 19 22:06:54 2000 by makisara@kai.makisara.local
+   Last modified: Sun Apr 23 23:41:32 2000 by makisara@kai.makisara.local
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -791,15 +791,6 @@
                                     (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
                                     STp->drv_buffer));
 		}
-
-		if (STp->block_size > (STp->buffer)->buffer_size &&
-		    !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
-			printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n",
-                               dev, STp->block_size);
-			scsi_release_request(SRpnt);
-			retval = (-EIO);
-			goto err_out;
-		}
 		STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
 	}
 	scsi_release_request(SRpnt);
@@ -1032,7 +1023,8 @@
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	ssize_t total;
-	ssize_t i, do_count, blks, retval, transfer;
+	ssize_t i, do_count, blks, transfer;
+	ssize_t retval = 0;
 	int write_threshold;
 	int doing_write = 0;
 	static unsigned char cmd[MAX_COMMAND_SIZE];
@@ -1047,6 +1039,9 @@
 	STp = scsi_tapes[dev];
 	read_unlock(&st_dev_arr_lock);
 
+	if (down_interruptible(&STp->lock))
+		return -ERESTARTSYS;
+
 	/*
 	 * If we are in the middle of error recovery, don't let anyone
 	 * else try and use this device.  Also, if error recovery fails, it
@@ -1054,59 +1049,86 @@
 	 * access to the device is prohibited.
 	 */
 	if (!scsi_block_when_processing_errors(STp->device)) {
-		return -ENXIO;
+		retval = (-ENXIO);
+		goto out;
 	}
 
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
-		return -ENXIO;
+		retval = (-ENXIO);
+		goto out;
 	}
 
 	if (STp->ready != ST_READY) {
 		if (STp->ready == ST_NO_TAPE)
-			return (-ENOMEDIUM);
+			retval = (-ENOMEDIUM);
 		else
-			return (-EIO);
+			retval = (-EIO);
+		goto out;
 	}
 
 	STm = &(STp->modes[STp->current_mode]);
-	if (!STm->defined)
-		return (-ENXIO);
+	if (!STm->defined) {
+		retval = (-ENXIO);
+		goto out;
+	}
 	if (count == 0)
-		return 0;
+		goto out;
 
 	/*
 	 * If there was a bus reset, block further access
 	 * to this device.
 	 */
-	if (STp->device->was_reset)
-		return (-EIO);
+	if (STp->device->was_reset) {
+		retval = (-EIO);
+		goto out;
+	}
 
         DEB(
 	if (!STp->in_use) {
 		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
-		return (-EIO);
+		retval = (-EIO);
+		goto out;
 	} ) /* end DEB */
 
 	/* Write must be integral number of blocks */
 	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
 		printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n",
 		       dev);
-		return (-EIO);
+		retval = (-EINVAL);
+		goto out;
 	}
 
 	if (STp->can_partitions &&
 	    (retval = update_partition(STp)) < 0)
-		return retval;
+		goto out;
 	STps = &(STp->ps[STp->partition]);
 
-	if (STp->write_prot)
-		return (-EACCES);
+	if (STp->write_prot) {
+		retval = (-EACCES);
+		goto out;
+	}
 
-	if (STp->block_size == 0 &&
-	    count > (STp->buffer)->buffer_size &&
-	    !enlarge_buffer(STp->buffer, count, STp->restr_dma))
-		return (-EOVERFLOW);
+	if (STp->block_size == 0) {
+		if (STp->max_block > 0 &&
+		    (count < STp->min_block || count > STp->max_block)) {
+			retval = (-EINVAL);
+			goto out;
+		}
+		if (count > (STp->buffer)->buffer_size &&
+		    !enlarge_buffer(STp->buffer, count, STp->restr_dma)) {
+			retval = (-EOVERFLOW);
+			goto out;
+		}
+	}
+	if ((STp->buffer)->buffer_blocks < 1) {
+		/* Fixed block mode with too small buffer */
+		if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
+			retval = (-EOVERFLOW);
+			goto out;
+		}
+		(STp->buffer)->buffer_blocks = 1;
+	}
 
 	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
 	    !st_int_ioctl(STp, MTLOCK, 0))
@@ -1115,19 +1137,21 @@
 	if (STps->rw == ST_READING) {
 		retval = flush_buffer(STp, 0);
 		if (retval)
-			return retval;
+			goto out;
 		STps->rw = ST_WRITING;
 	} else if (STps->rw != ST_WRITING &&
 		   STps->drv_file == 0 && STps->drv_block == 0) {
 		if ((retval = set_mode_densblk(STp, STm)) < 0)
-			return retval;
+			goto out;
 		if (STm->default_compression != ST_DONT_TOUCH &&
 		    !(STp->compression_changed)) {
 			if (st_compression(STp, (STm->default_compression == ST_YES))) {
 				printk(KERN_WARNING "st%d: Can't set default compression.\n",
 				       dev);
-				if (modes_defined)
-					return (-EINVAL);
+				if (modes_defined) {
+					retval = (-EINVAL);
+					goto out;
+				}
 			}
 		}
 	}
@@ -1144,22 +1168,30 @@
 		}
 	}
 
-	if (STps->eof == ST_EOM_OK)
-		return (-ENOSPC);
-	else if (STps->eof == ST_EOM_ERROR)
-		return (-EIO);
+	if (STps->eof == ST_EOM_OK) {
+		retval = (-ENOSPC);
+		goto out;
+	}
+	else if (STps->eof == ST_EOM_ERROR) {
+		retval = (-EIO);
+		goto out;
+	}
 
 	/* Check the buffer readability in cases where copy_user might catch
 	   the problems after some tape movement. */
 	if (STp->block_size != 0 &&
 	    (copy_from_user(&i, buf, 1) != 0 ||
-	     copy_from_user(&i, buf + count - 1, 1) != 0))
-		return (-EFAULT);
+	     copy_from_user(&i, buf + count - 1, 1) != 0)) {
+		retval = (-EFAULT);
+		goto out;
+	}
 
 	if (!STm->do_buffer_writes) {
 #if 0
-		if (STp->block_size != 0 && (count % STp->block_size) != 0)
-			return (-EIO);	/* Write must be integral number of blocks */
+		if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+			retval = (-EINVAL);	/* Write must be integral number of blocks */
+			goto out;
+		}
 #endif
 		write_threshold = 1;
 	} else
@@ -1191,11 +1223,8 @@
 
 		i = append_to_buffer(b_point, STp->buffer, do_count);
 		if (i) {
-			if (SRpnt != NULL) {
-				scsi_release_request(SRpnt);
-				SRpnt = NULL;
-			}
-			return i;
+			retval = i;
+			goto out;
 		}
 
 		if (STp->block_size == 0)
@@ -1211,8 +1240,10 @@
 
 		SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
 				   STp->timeout, MAX_WRITE_RETRIES, TRUE);
-		if (!SRpnt)
-			return (STp->buffer)->syscall_result;
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			goto out;
+		}
 
 		if ((STp->buffer)->syscall_result != 0) {
                         DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev));
@@ -1267,9 +1298,8 @@
 			(STp->buffer)->buffer_bytes = 0;
 			STp->dirty = 0;
 			if (count < total)
-				return total - count;
-			else
-				return retval;
+				retval = total - count;
+			goto out;
 		}
 		filp->f_pos += do_count;
 		b_point += do_count;
@@ -1287,20 +1317,16 @@
 		STp->dirty = 1;
 		i = append_to_buffer(b_point, STp->buffer, count);
 		if (i) {
-			if (SRpnt != NULL) {
-				scsi_release_request(SRpnt);
-				SRpnt = NULL;
-			}
-			return i;
+			retval = i;
+			goto out;
 		}
 		filp->f_pos += count;
 		count = 0;
 	}
 
 	if (doing_write && (STp->buffer)->syscall_result != 0) {
-		scsi_release_request(SRpnt);
-		SRpnt = NULL;
-		return (STp->buffer)->syscall_result;
+		retval = (STp->buffer)->syscall_result;
+		goto out;
 	}
 
 	if (STm->do_async_writes &&
@@ -1328,18 +1354,24 @@
 		SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing,
 				   SCSI_DATA_WRITE, STp->timeout,
 				   MAX_WRITE_RETRIES, FALSE);
-		if (SRpnt == NULL)
-			return (STp->buffer)->syscall_result;
+		if (SRpnt == NULL) {
+			retval = (STp->buffer)->syscall_result;
+			goto out;
+		}
+		SRpnt = NULL;  /* Prevent releasing this request! */
 
-	} else if (SRpnt != NULL) {
-		scsi_release_request(SRpnt);
-		SRpnt = NULL;
 	}
 	STps->at_sm &= (total == 0);
 	if (total > 0)
 		STps->eof = ST_NOEOF;
+	retval = total;
+
+ out:
+	if (SRpnt != NULL)
+		scsi_release_request(SRpnt);
+	up(&STp->lock);
 
-	return (total);
+	return retval;
 }
 
 /* Read data from the tape. Returns zero in the normal case, one if the
@@ -1516,6 +1548,7 @@
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	ssize_t total;
+	ssize_t retval = 0;
 	ssize_t i, transfer;
 	int special;
 	Scsi_Request *SRpnt = NULL;
@@ -1528,6 +1561,9 @@
 	STp = scsi_tapes[dev];
 	read_unlock(&st_dev_arr_lock);
 
+	if (down_interruptible(&STp->lock))
+		return -ERESTARTSYS;
+
 	/*
 	 * If we are in the middle of error recovery, don't let anyone
 	 * else try and use this device.  Also, if error recovery fails, it
@@ -1535,41 +1571,65 @@
 	 * access to the device is prohibited.
 	 */
 	if (!scsi_block_when_processing_errors(STp->device)) {
-		return -ENXIO;
+		retval = (-ENXIO);
+		goto out;
 	}
 
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
-		return -ENXIO;
+		retval = (-ENXIO);
+		goto out;
 	}
 
 	if (STp->ready != ST_READY) {
 		if (STp->ready == ST_NO_TAPE)
-			return (-ENOMEDIUM);
+			retval = (-ENOMEDIUM);
 		else
-			return (-EIO);
+			retval = (-EIO);
+		goto out;
 	}
 	STm = &(STp->modes[STp->current_mode]);
-	if (!STm->defined)
-		return (-ENXIO);
+	if (!STm->defined) {
+		retval = (-ENXIO);
+		goto out;
+	}
         DEB(
 	if (!STp->in_use) {
 		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
-		return (-EIO);
+		retval = (-EIO);
+		goto out;
 	} ) /* end DEB */
 
 	if (STp->can_partitions &&
-	    (total = update_partition(STp)) < 0)
-		return total;
+	    (retval = update_partition(STp)) < 0)
+		goto out;
 
-	if (STp->block_size == 0 &&
-	    count > (STp->buffer)->buffer_size &&
-	    !enlarge_buffer(STp->buffer, count, STp->restr_dma))
-		return (-EOVERFLOW);
+	if (STp->block_size == 0) {
+		if (STp->max_block > 0 &&
+		    (count < STp->min_block || count > STp->max_block)) {
+			retval = (-EINVAL);
+			goto out;
+		}
+		if (count > (STp->buffer)->buffer_size &&
+		    !enlarge_buffer(STp->buffer, count, STp->restr_dma)) {
+			retval = (-EOVERFLOW);
+			goto out;
+		}
+	}
+	if ((STp->buffer)->buffer_blocks < 1) {
+		/* Fixed block mode with too small buffer */
+		if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
+			retval = (-EOVERFLOW);
+			goto out;
+		}
+		(STp->buffer)->buffer_blocks = 1;
+	}
 
 	if (!(STm->do_read_ahead) && STp->block_size != 0 &&
-	    (count % STp->block_size) != 0)
-		return (-EIO);	/* Read must be integral number of blocks */
+	    (count % STp->block_size) != 0) {
+		retval = (-EINVAL);	/* Read must be integral number of blocks */
+		goto out;
+	}
 
 	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
 	    !st_int_ioctl(STp, MTLOCK, 0))
@@ -1577,9 +1637,9 @@
 
 	STps = &(STp->ps[STp->partition]);
 	if (STps->rw == ST_WRITING) {
-		transfer = flush_buffer(STp, 0);
-		if (transfer)
-			return transfer;
+		retval = flush_buffer(STp, 0);
+		if (retval)
+			goto out;
 		STps->rw = ST_READING;
 	}
         DEB(
@@ -1592,9 +1652,11 @@
 	    STps->eof >= ST_EOD_1) {
 		if (STps->eof < ST_EOD) {
 			STps->eof += 1;
-			return 0;
+			retval = 0;
+			goto out;
 		}
-		return (-EIO);	/* EOM or Blank Check */
+		retval = (-EIO);	/* EOM or Blank Check */
+		goto out;
 	}
 
 	/* Check the buffer writability before any tape movement. Don't alter
@@ -1602,8 +1664,10 @@
 	if (copy_from_user(&i, buf, 1) != 0 ||
 	    copy_to_user(buf, &i, 1) != 0 ||
 	    copy_from_user(&i, buf + count - 1, 1) != 0 ||
-	    copy_to_user(buf + count - 1, &i, 1) != 0)
-		return (-EFAULT);
+	    copy_to_user(buf + count - 1, &i, 1) != 0) {
+		retval = (-EFAULT);
+		goto out;
+	}
 
 	STps->rw = ST_READING;
 
@@ -1615,10 +1679,8 @@
 		if ((STp->buffer)->buffer_bytes == 0) {
 			special = read_tape(STp, count - total, &SRpnt);
 			if (special < 0) {	/* No need to continue read */
-				if (SRpnt != NULL) {
-					scsi_release_request(SRpnt);
-				}
-				return special;
+				retval = special;
+				goto out;
 			}
 		}
 
@@ -1635,11 +1697,8 @@
 			    (STp->buffer)->buffer_bytes : count - total;
 			i = from_buffer(STp->buffer, buf, transfer);
 			if (i) {
-				if (SRpnt != NULL) {
-					scsi_release_request(SRpnt);
-					SRpnt = NULL;
-				}
-				return i;
+				retval = i;
+				goto out;
 			}
 			filp->f_pos += transfer;
 			buf += transfer;
@@ -1652,11 +1711,6 @@
 	}			/* for (total = 0, special = 0;
                                    total < count && !special; ) */
 
-	if (SRpnt != NULL) {
-		scsi_release_request(SRpnt);
-		SRpnt = NULL;
-	}
-
 	/* Change the eof state if no data from tape or buffer */
 	if (total == 0) {
 		if (STps->eof == ST_FM_HIT) {
@@ -1673,8 +1727,16 @@
 			STps->eof = ST_EOD;
 	} else if (STps->eof == ST_FM)
 		STps->eof = ST_NOEOF;
+	retval = total;
+
+ out:
+	if (SRpnt != NULL) {
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
+	}
+	up(&STp->lock);
 
-	return total;
+	return retval;
 }
 
 
@@ -2236,9 +2298,9 @@
 			return (-EIO);	/* Not allowed if data in buffer */
 		if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
 		    (arg & MT_ST_BLKSIZE_MASK) != 0 &&
+		    STp->max_block > 0 &&
 		    ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
-		     (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
-		     (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) {
+		     (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) {
 			printk(KERN_WARNING "st%d: Illegal block size.\n", dev);
 			return (-EINVAL);
 		}
@@ -2745,6 +2807,7 @@
 		    unsigned int cmd_in, unsigned long arg)
 {
 	int i, cmd_nr, cmd_type, bt;
+	int retval = 0;
 	unsigned int blk;
 	Scsi_Tape *STp;
 	ST_mode *STm;
@@ -2755,10 +2818,14 @@
 	STp = scsi_tapes[dev];
 	read_unlock(&st_dev_arr_lock);
 
+	if (down_interruptible(&STp->lock))
+		return -ERESTARTSYS;
+
         DEB(
 	if (debugging && !STp->in_use) {
 		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
-		return (-EIO);
+		retval = (-EIO);
+		goto out;
 	} ) /* end DEB */
 
 	STm = &(STp->modes[STp->current_mode]);
@@ -2771,7 +2838,8 @@
 	 * access to the device is prohibited.
 	 */
 	if (!scsi_block_when_processing_errors(STp->device)) {
-		return -ENXIO;
+		retval = (-ENXIO);
+		goto out;
 	}
 	cmd_type = _IOC_TYPE(cmd_in);
 	cmd_nr = _IOC_NR(cmd_in);
@@ -2779,21 +2847,29 @@
 	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
 		struct mtop mtc;
 
-		if (_IOC_SIZE(cmd_in) != sizeof(mtc))
-			return (-EINVAL);
+		if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
+			retval = (-EINVAL);
+			goto out;
+		}
 
 		i = copy_from_user((char *) &mtc, (char *) arg, sizeof(struct mtop));
-		if (i)
-			return (-EFAULT);
+		if (i) {
+			retval = (-EFAULT);
+			goto out;
+		}
 
 		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
 			printk(KERN_WARNING
                                "st%d: MTSETDRVBUFFER only allowed for root.\n", dev);
-			return (-EPERM);
+			retval = (-EPERM);
+			goto out;
 		}
 		if (!STm->defined &&
-		    (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0))
-			return (-ENXIO);
+		    (mtc.mt_op != MTSETDRVBUFFER &&
+		     (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
+			retval = (-ENXIO);
+			goto out;
+		}
 
 		if (!(STp->device)->was_reset) {
 
@@ -2822,8 +2898,10 @@
 				    mtc.mt_op == MTCOMPRESSION;
 			}
 			i = flush_buffer(STp, i);
-			if (i < 0)
-				return i;
+			if (i < 0) {
+				retval = i;
+				goto out;
+			}
 		} else {
 			/*
 			 * If there was a bus reset, block further access
@@ -2835,8 +2913,10 @@
 			    mtc.mt_op != MTRETEN &&
 			    mtc.mt_op != MTERASE &&
 			    mtc.mt_op != MTSEEK &&
-			    mtc.mt_op != MTEOM)
-				return (-EIO);
+			    mtc.mt_op != MTEOM) {
+				retval = (-EIO);
+				goto out;
+			}
 			STp->device->was_reset = 0;
 			if (STp->door_locked != ST_UNLOCKED &&
 			    STp->door_locked != ST_LOCK_FAILS) {
@@ -2858,8 +2938,10 @@
 			st_int_ioctl(STp, MTUNLOCK, 0);	/* Ignore result! */
 
 		if (mtc.mt_op == MTSETDRVBUFFER &&
-		    (mtc.mt_count & MT_ST_OPTIONS) != 0)
-			return st_set_options(STp, mtc.mt_count);
+		    (mtc.mt_count & MT_ST_OPTIONS) != 0) {
+			retval = st_set_options(STp, mtc.mt_count);
+			goto out;
+		}
 
 		if (mtc.mt_op == MTSETPART) {
 			if (!STp->can_partitions ||
@@ -2871,7 +2953,8 @@
 			if (mtc.mt_count >= STp->nbr_partitions)
 				return (-EINVAL);
 			STp->new_partition = mtc.mt_count;
-			return 0;
+			retval = 0;
+			goto out;
 		}
 
 		if (mtc.mt_op == MTMKPART) {
@@ -2888,39 +2971,52 @@
 			STp->partition = STp->new_partition = 0;
 			STp->nbr_partitions = 1;	/* Bad guess ?-) */
 			STps->drv_block = STps->drv_file = 0;
-			return 0;
+			retval = 0;
+			goto out;
 		}
 
 		if (mtc.mt_op == MTSEEK) {
 			i = set_location(STp, mtc.mt_count, STp->new_partition, 0);
 			if (!STp->can_partitions)
 				STp->ps[0].rw = ST_IDLE;
-			return i;
+			retval = i;
+			goto out;
 		}
 
 		if (STp->can_partitions && STp->ready == ST_READY &&
-		    (i = update_partition(STp)) < 0)
-			return i;
+		    (i = update_partition(STp)) < 0) {
+			retval = i;
+			goto out;
+		}
 
 		if (mtc.mt_op == MTCOMPRESSION)
-			return st_compression(STp, (mtc.mt_count & 1));
+			retval = st_compression(STp, (mtc.mt_count & 1));
 		else
-			return st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
+			retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
+		goto out;
+	}
+	if (!STm->defined) {
+		retval = (-ENXIO);
+		goto out;
 	}
-	if (!STm->defined)
-		return (-ENXIO);
 
-	if ((i = flush_buffer(STp, FALSE)) < 0)
-		return i;
+	if ((i = flush_buffer(STp, FALSE)) < 0) {
+		retval = i;
+		goto out;
+	}
 	if (STp->can_partitions &&
-	    (i = update_partition(STp)) < 0)
-		return i;
+	    (i = update_partition(STp)) < 0) {
+		retval = i;
+		goto out;
+	}
 
 	if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
 		struct mtget mt_status;
 
-		if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
-			 return (-EINVAL);
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
+			 retval = (-EINVAL);
+			 goto out;
+		}
 
 		mt_status.mt_type = STp->tape_type;
 		mt_status.mt_dsreg =
@@ -2972,25 +3068,37 @@
 
 		i = copy_to_user((char *) arg, (char *) &(mt_status),
 				 sizeof(struct mtget));
-		if (i)
-			return (-EFAULT);
+		if (i) {
+			retval = (-EFAULT);
+			goto out;
+		}
 
 		STp->recover_reg = 0;		/* Clear after read */
-		return 0;
+		retval = 0;
+		goto out;
 	}			/* End of MTIOCGET */
 	if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
 		struct mtpos mt_pos;
-		if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
-			 return (-EINVAL);
-		if ((i = get_location(STp, &blk, &bt, 0)) < 0)
-			return i;
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
+			 retval = (-EINVAL);
+			 goto out;
+		}
+		if ((i = get_location(STp, &blk, &bt, 0)) < 0) {
+			retval = i;
+			goto out;
+		}
 		mt_pos.mt_blkno = blk;
 		i = copy_to_user((char *) arg, (char *) (&mt_pos), sizeof(struct mtpos));
 		if (i)
-			return (-EFAULT);
-		return 0;
+			retval = (-EFAULT);
+		goto out;
 	}
+	up(&STp->lock);
 	return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+
+ out:
+	up(&STp->lock);
+	return retval;
 }
 
 
@@ -3469,6 +3577,7 @@
 
 	tpnt->density_changed = tpnt->compression_changed =
 	    tpnt->blksize_changed = FALSE;
+	init_MUTEX(&tpnt->lock);
 
 	st_template.nr_dev++;
 	write_unlock_irqrestore(&st_dev_arr_lock, flags);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.3.99-pre5/linux/drivers/scsi/st.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/st.h	Mon Apr 24 13:54:22 2000
@@ -66,7 +66,8 @@
 typedef struct {
 	kdev_t devt;
 	Scsi_Device *device;
-	struct semaphore sem;
+	struct semaphore lock;	/* For serialization */
+	struct semaphore sem;	/* For SCSI commands */
 	ST_buffer *buffer;
 
 	/* Drive characteristics */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h
--- v2.3.99-pre5/linux/drivers/scsi/st_options.h	Tue Mar 14 19:10:40 2000
+++ linux/drivers/scsi/st_options.h	Mon Apr 24 13:54:22 2000
@@ -3,7 +3,7 @@
 
    Copyright 1995-2000 Kai Makisara.
 
-   Last modified: Sat Mar 11 10:32:00 2000 by makisara@kai.makisara.local
+   Last modified: Sat Apr 22 14:47:02 2000 by makisara@kai.makisara.local
 */
 
 #ifndef _ST_OPTIONS_H
@@ -30,7 +30,7 @@
    SENSE. */
 #define ST_DEFAULT_BLOCK 0
 
-/* The tape driver buffer size in kilobytes. */
+/* The tape driver buffer size in kilobytes. Must be non-zero. */
 #define ST_BUFFER_BLOCKS 32
 
 /* The number of kilobytes of data in the buffer that triggers an
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.3.99-pre5/linux/drivers/scsi/sym53c8xx.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/scsi/sym53c8xx.c	Mon Apr 24 16:16:13 2000
@@ -55,7 +55,7 @@
 */
 
 /*
-**	March 6 2000, sym53c8xx 1.5k
+**	April 24 2000, sym53c8xx 1.5m
 **
 **	Supported SCSI features:
 **	    Synchronous data transfers
@@ -84,7 +84,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5l"
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5m"
 
 /* #define DEBUG_896R1 */
 #define SCSI_NCR_OPTIMIZE_896
@@ -5241,7 +5241,7 @@
 	**	64 bit (53C895A or 53C896) ?
 	*/
 	if (np->features & FE_64BIT)
-#if BITS_PER_LONG > 32
+#ifdef SCSI_NCR_USE_64BIT_DAC
 		np->rv_ccntl1	|= (XTIMOD | EXTIBMV);
 #else
 		np->rv_ccntl1	|= (DDAC);
@@ -11152,7 +11152,7 @@
 **	code will get more complex later).
 */
 
-#if BITS_PER_LONG > 32
+#ifdef SCSI_NCR_USE_64BIT_DAC
 #define SCATTER_ONE(data, badd, len)					\
 	(data)->addr = cpu_to_scr(badd);				\
 	(data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len);
@@ -11845,7 +11845,7 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
-	return 0;
+	return 1;
 }
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_comm.h	Tue Apr 11 15:09:19 2000
+++ linux/drivers/scsi/sym53c8xx_comm.h	Mon Apr 24 16:16:13 2000
@@ -2178,7 +2178,7 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
-	return 0;
+	return 1;
 }
 
 /*===================================================================
@@ -2817,10 +2817,12 @@
 				if (!ncr_attach (tpnt, attach_count, devp))
 					attach_count++;
 			}
+#if 0	/* Restore previous behaviour of ncr53c8xx driver */
 			else if (!(driver_setup.use_nvram & 0x80))
 				printk(KERN_INFO NAME53C8XX
 				       ": 53c%s state OFF thus not attached\n",
 				       devp->chip.name);
+#endif
 			else
 				continue;
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h
--- v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_defs.h	Tue Jan 11 22:31:41 2000
+++ linux/drivers/scsi/sym53c8xx_defs.h	Wed Apr 26 15:30:47 2000
@@ -182,6 +182,13 @@
 #endif
 
 /*
+ * Should we enable DAC cycles on sparc64 platforms?
+ * Until further investigation we do not enable it
+ * anywhere at the moment.
+ */
+#undef SCSI_NCR_USE_64BIT_DAC
+
+/*
  * Sync transfer frequency at startup.
  * Allow from 5Mhz to 40Mhz default 20 Mhz.
  */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.3.99-pre5/linux/drivers/scsi/tmscsim.c	Thu Nov 11 20:11:49 1999
+++ linux/drivers/scsi/tmscsim.c	Fri Apr 21 16:08:45 2000
@@ -212,7 +212,7 @@
 
 # if USE_SPINLOCKS == 3 /* both */
 
-#  if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+#  if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0
 #   define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
 #  else
 #   define DC390_LOCKA_INIT
@@ -241,7 +241,7 @@
 
 #  if USE_SPINLOCKS == 2 /* adapter specific locks */
 
-#   if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+#   if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0
 #    define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
 #   else
 #    define DC390_LOCKA_INIT
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h
--- v2.3.99-pre5/linux/drivers/scsi/tmscsim.h	Fri Dec 25 16:41:39 1998
+++ linux/drivers/scsi/tmscsim.h	Fri Apr 21 16:08:45 2000
@@ -8,6 +8,8 @@
 #ifndef _TMSCSIM_H
 #define _TMSCSIM_H
 
+#include <linux/config.h>
+
 #define IRQ_NONE 255
 
 #define MAX_ADAPTER_NUM 	4
@@ -210,7 +212,7 @@
 UCHAR		msgin123[4];
 UCHAR		DCBmap[MAX_SCSI_ID];
 
-#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0)
+#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0)
 spinlock_t	lock;
 #endif
 UCHAR		sel_timeout;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.3.99-pre5/linux/drivers/sound/Config.in	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sound/Config.in	Fri Apr 21 16:08:45 2000
@@ -17,6 +17,7 @@
         bool '    Separate rear out jack' CONFIG_SOUND_CMPCI_REAR
     fi
 fi
+dep_tristate '  Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
 dep_tristate '  Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
 dep_tristate '  Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
 dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
@@ -97,6 +98,7 @@
       bool '      16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_SOUND_GUS16 
       bool '      GUS MAX support' CONFIG_SOUND_GUSMAX
    fi
+   dep_tristate '    Intel ICH audio support' CONFIG_SOUND_ICH $CONFIG_SOUND_OSS
    dep_tristate '    Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND_OSS
    dep_tristate '    MediaTrix AudioTrix Pro support' CONFIG_SOUND_TRIX $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_TRIX" = "y" ]; then
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.3.99-pre5/linux/drivers/sound/Makefile	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/Makefile	Fri Apr 21 16:08:45 2000
@@ -10,8 +10,7 @@
 SUB_DIRS	:= 
 MOD_SUB_DIRS	:=
 MOD_IN_SUB_DIRS	:=
-ALL_SUB_DIRS	:= $(SUB_DIRS)
-
+ALL_SUB_DIRS	:= $(SUB_DIRS) emu10k1
 
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
@@ -72,6 +71,7 @@
 obj-$(CONFIG_SOUND_MSNDPIN)	+= msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_VWSND)	+= vwsnd.o
 obj-$(CONFIG_SOUND_NM256)	+= nm256_audio.o ac97.o
+obj-$(CONFIG_SOUND_ICH)		+= i810_audio.o ac97.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
 obj-$(CONFIG_SOUND_CMPCI)	+= cmpci.o
 obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
@@ -80,6 +80,15 @@
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
 obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
 
+ifeq ($(CONFIG_SOUND_EMU10K1),y)
+  SUB_DIRS          += emu10k1
+  obj-y += emu10k1/emu10k1.o
+else
+  ifeq ($(CONFIG_SOUND_EMU10K1),m)
+     MOD_SUB_DIRS   += emu10k1
+  endif
+endif
+
 ifeq ($(CONFIG_DMASOUND),y)
   SUB_DIRS += dmasound
   MOD_SUB_DIRS += dmasound
@@ -138,8 +147,7 @@
 # Translate to Rules.make lists.
 
 O_TARGET	:= sounddrivers.o
-# This is a nice idea but needs depmod altering
-#MOD_LIST_NAME	:= SOUND_MODULES
+MOD_LIST_NAME	:= SOUND_MODULES
 
 O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
 OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.3.99-pre5/linux/drivers/sound/ad1848.c	Fri Mar 10 16:40:44 2000
+++ linux/drivers/sound/ad1848.c	Wed Apr 12 09:47:26 2000
@@ -27,6 +27,7 @@
  * Alan Cox		: reformatted. Fixed SMP bugs. Moved to kernel alloc/free
  *		          of irqs. Use dev_id.
  * Christoph Hellwig	: adapted to module_init/module_exit
+ * Aki Laukkanen	: added power management support
  *
  * Status:
  *		Tested. Believed fully functional.
@@ -36,6 +37,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/stddef.h>
+#include <linux/pm.h>
 
 #include "soundmodule.h"
 
@@ -52,6 +54,7 @@
 	int             irq;
 	int             dma1, dma2;
 	int             dual_dma;	/* 1, when two DMA channels allocated */
+	int 		subtype;
 	unsigned char   MCE_bit;
 	unsigned char   saved_regs[32];
 	int             debug_flag;
@@ -87,6 +90,9 @@
 	int             irq_ok;
 	mixer_ents     *mix_devices;
 	int             mixer_output_port;
+
+	/* Power management */
+	struct		pm_dev *pmdev;
 } ad1848_info;
 
 typedef struct ad1848_port_info
@@ -100,7 +106,9 @@
 }
 ad1848_port_info;
 
+static struct address_info cfg;
 static int nr_ad1848_devs = 0;
+
 int deskpro_xl = 0;
 int deskpro_m = 0;
 int soundpro = 0;
@@ -163,11 +171,11 @@
 static void     ad1848_halt_input(int dev);
 static void     ad1848_halt_output(int dev);
 static void     ad1848_trigger(int dev, int bits);
+static int	ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);
 
 #ifndef EXCLUDE_TIMERS
 static int ad1848_tmr_install(int dev);
 static void ad1848_tmr_reprogram(int dev);
-
 #endif
 
 static int ad_read(ad1848_info * devc, int reg)
@@ -1415,7 +1423,7 @@
 		if (devc->model == MD_IWAVE)
 			ad_write(devc, 12, 0x6c);	/* Select codec mode 3 */
 
-		if (devc-> model != MD_1845_SSCAPE)
+		if (devc->model != MD_1845_SSCAPE)
 			for (i = 16; i < 32; i++)
 				ad_write(devc, i, init_values[i]);
 
@@ -1849,7 +1857,6 @@
 	 *   The actually used IRQ is ABS(irq).
 	 */
 
-
 	int my_dev;
 	char dev_name[100];
 	int e;
@@ -1863,6 +1870,7 @@
 	devc->timer_ticks = 0;
 	devc->dma1 = dma_playback;
 	devc->dma2 = dma_capture;
+	devc->subtype = cfg.card_subtype;
 	devc->audio_flags = DMA_AUTOMODE;
 	devc->playback_dev = devc->record_dev = 0;
 	if (name != NULL)
@@ -1915,6 +1923,10 @@
 
 	nr_ad1848_devs++;
 
+	devc->pmdev = pm_register(PM_ISA_DEV, my_dev, ad1848_pm_callback);
+	if (devc->pmdev)
+		devc->pmdev->data = devc;
+
 	ad1848_init_hw(devc);
 
 	if (irq > 0)
@@ -1950,7 +1962,7 @@
 				devc->irq_ok = 1;
 			}
 #else
-			devc->irq_ok=1;
+			devc->irq_ok = 1;
 #endif			
 		}
 		else
@@ -2076,6 +2088,9 @@
 		if(mixer>=0)
 			sound_unload_mixerdev(mixer);
 
+		if (devc->pmdev)
+			pm_unregister(devc->pmdev);
+
 		nr_ad1848_devs--;
 		for ( ; i < nr_ad1848_devs ; i++)
 			adev_info[i] = adev_info[i+1];
@@ -2507,7 +2522,8 @@
 		hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
 						    hw_config->irq,
 						    hw_config->dma,
-				     hw_config->dma2, 0, hw_config->osp);
+						    hw_config->dma2, 0, 
+						    hw_config->osp);
 		request_region(hw_config->io_base, 4, "WSS config");
 		return;
 	}
@@ -2562,10 +2578,9 @@
 
 	outb((bits | dma_bits[dma] | dma2_bit), config_port);	/* Write IRQ+DMA setup */
 
-	hw_config->slots[0] = ad1848_init("MSS audio codec", hw_config->io_base + 4,
+	hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
 					  hw_config->irq,
-					  dma,
-					  dma2, 0,
+					  dma, dma2, 0,
 					  hw_config->osp);
 	request_region(hw_config->io_base, 4, "WSS config");
 }
@@ -2692,6 +2707,83 @@
 }
 #endif /* EXCLUDE_TIMERS */
 
+static int ad1848_suspend(ad1848_info *devc)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	ad_mute(devc);
+	
+	restore_flags(flags);
+	return 0;
+}
+
+static int ad1848_resume(ad1848_info *devc)
+{
+	unsigned long flags;
+	int mixer_levels[32], i;
+
+	save_flags(flags);
+	cli();
+
+	/* store old mixer levels */
+	memcpy(mixer_levels, devc->levels, sizeof (mixer_levels));  
+	ad1848_init_hw(devc);
+
+	/* restore mixer levels */
+	for (i = 0; i < 32; i++)
+		ad1848_mixer_set(devc, devc->dev_no, mixer_levels[i]);
+
+	if (!devc->subtype) {
+		static signed char interrupt_bits[12] = { -1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20 };
+		static char dma_bits[4] = { 1, 2, 0, 3 };
+
+		signed char bits;
+		char dma2_bit = 0;
+
+		int config_port = devc->base + 0;
+
+		bits = interrupt_bits[devc->irq];
+		if (bits == -1) {
+			printk(KERN_ERR "MSS: Bad IRQ %d\n", devc->irq);
+			return -1;
+		}
+
+		outb((bits | 0x40), config_port); 
+
+		if (devc->dma2 != -1 && devc->dma2 != devc->dma1)
+			if ( (devc->dma1 == 0 && devc->dma2 == 1) ||
+			     (devc->dma1 == 1 && devc->dma2 == 0) ||
+			     (devc->dma1 == 3 && devc->dma2 == 0))
+				dma2_bit = 0x04;
+
+		outb((bits | dma_bits[devc->dma1] | dma2_bit), config_port);
+	}
+
+	restore_flags(flags);
+      	return 0;
+}
+
+static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) 
+{
+	ad1848_info *devc = dev->data;
+	if (devc) {
+		DEB(printk("ad1848: pm event received: 0x%x\n", rqst));
+
+		switch (rqst) {
+		case PM_SUSPEND:
+			ad1848_suspend(devc);
+			break;
+		case PM_RESUME:
+			ad1848_resume(devc);
+			break;
+		}
+	}
+	return 0;
+}
+
 
 EXPORT_SYMBOL(ad1848_detect);
 EXPORT_SYMBOL(ad1848_init);
@@ -2707,8 +2799,6 @@
 static int __initdata dma = -1;
 static int __initdata dma2 = -1;
 static int __initdata type = 0;
-
-static struct address_info cfg;
 
 MODULE_PARM(io, "i");                   /* I/O for a raw AD1848 card */
 MODULE_PARM(irq, "i");                  /* IRQ to use */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.3.99-pre5/linux/drivers/sound/cmpci.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/cmpci.c	Fri Apr 21 13:23:56 2000
@@ -1364,6 +1364,7 @@
 	return ret;
 }
 
+/* No kernel lock - fine (we have our own spinlock) */
 static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct cm_state *s = (struct cm_state *)file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v2.3.99-pre5/linux/drivers/sound/dmabuf.c	Tue Mar 14 19:10:40 2000
+++ linux/drivers/sound/dmabuf.c	Fri Apr 21 13:24:59 2000
@@ -1218,6 +1218,7 @@
 	}
 }
 
+/* No kernel lock - DMAbuf_activate_recording protected by global cli/sti */
 static unsigned int poll_input(struct file * file, int dev, poll_table *wait)
 {
 	struct audio_operations *adev = audio_devs[dev];
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound.h linux/drivers/sound/dmasound/dmasound.h
--- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound.h	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/dmasound/dmasound.h	Tue Apr 25 17:58:46 2000
@@ -1,6 +1,6 @@
 
 /*
- *  linux/drivers/sound/dmasound.h
+ *  linux/drivers/sound/dmasound/dmasound.h
  *
  *
  *  Minor numbers for the sound driver.
@@ -89,7 +89,11 @@
      */
 
 extern int dmasound_init(void);
+#ifdef MODULE
 extern void dmasound_deinit(void);
+#else
+#define dmasound_deinit()	do { } while (0)
+#endif
 
 
     /*
@@ -106,7 +110,7 @@
     int (*irqinit)(void);
 #ifdef MODULE
     void (*irqcleanup)(void);
-#endif /* MODULE */
+#endif
     void (*init)(void);
     void (*silence)(void);
     int (*setFormat)(int);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_atari.c linux/drivers/sound/dmasound/dmasound_atari.c
--- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_atari.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/dmasound/dmasound_atari.c	Tue Apr 25 17:58:46 2000
@@ -1,10 +1,10 @@
 
 /*
- *  linux/drivers/sound/dmasound_atari.c
+ *  linux/drivers/sound/dmasound/dmasound_atari.c
  *
- *  Atari DMA Sound Driver
+ *  Atari TT and Falcon DMA Sound Driver
  *
- *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
  */
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_awacs.c linux/drivers/sound/dmasound/dmasound_awacs.c
--- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_awacs.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/dmasound/dmasound_awacs.c	Tue Apr 25 17:58:46 2000
@@ -1,10 +1,10 @@
 
 /*
- *  linux/drivers/sound/dmasound_awacs.c
+ *  linux/drivers/sound/dmasound/dmasound_awacs.c
  *
- *  PowerMac DMA Sound Driver
+ *  PowerMac `AWACS' and `Burgundy' DMA Sound Driver
  *
- *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
  */
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_core.c linux/drivers/sound/dmasound/dmasound_core.c
--- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_core.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/dmasound/dmasound_core.c	Tue Apr 25 17:58:46 2000
@@ -1,6 +1,6 @@
 
 /*
- *  linux/drivers/sound/dmasound.c
+ *  linux/drivers/sound/dmasound/dmasound_core.c
  *
  *
  *  OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for
@@ -1193,8 +1193,10 @@
 
 int __init dmasound_init(void)
 {
+#ifdef MODULE
 	if (irq_installed)
 		return -EBUSY;
+#endif
 
 	/* Set up sound queue, /dev/audio and /dev/dsp. */
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_paula.c linux/drivers/sound/dmasound/dmasound_paula.c
--- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_paula.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/dmasound/dmasound_paula.c	Tue Apr 25 17:58:46 2000
@@ -1,14 +1,15 @@
 
 /*
- *  linux/drivers/sound/dmasound_paula.c
+ *  linux/drivers/sound/dmasound/dmasound_paula.c
  *
- *  Amiga DMA Sound Driver
+ *  Amiga `Paula' DMA Sound Driver
  *
- *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
  */
 
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -18,6 +19,7 @@
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
+#include <asm/machdep.h>
 
 #include "dmasound.h"
 
@@ -76,6 +78,38 @@
 static void AmiPlay(void);
 static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);
 
+#ifdef CONFIG_HEARTBEAT
+
+    /*
+     *  Heartbeat interferes with sound since the 7 kHz low-pass filter and the
+     *  power LED are controlled by the same line.
+     */
+
+#ifdef CONFIG_APUS
+#define mach_heartbeat	ppc_md.heartbeat
+#endif
+
+static void (*saved_heartbeat)(int) = NULL;
+
+static inline void disable_heartbeat(void)
+{
+	if (mach_heartbeat) {
+	    saved_heartbeat = mach_heartbeat;
+	    mach_heartbeat = NULL;
+	}
+	AmiSetTreble(dmasound.treble);
+}
+
+static inline void enable_heartbeat(void)
+{
+	if (saved_heartbeat)
+	    mach_heartbeat = saved_heartbeat;
+}
+#else /* !CONFIG_HEARTBEAT */
+#define disable_heartbeat()	do { } while (0)
+#define enable_heartbeat()	do { } while (0)
+#endif /* !CONFIG_HEARTBEAT */
+
 
 /*** Mid level stuff *********************************************************/
 
@@ -285,6 +319,7 @@
 	custom.aud[0].audvol = custom.aud[1].audvol = 0;
 	custom.aud[2].audvol = custom.aud[3].audvol = 0;
 	custom.dmacon = AMI_AUDIO_OFF;
+	enable_heartbeat();
 }
 
 static void *AmiAlloc(unsigned int size, int flags)
@@ -350,8 +385,6 @@
 	for (i = 0; i < 4; i++)
 		custom.aud[i].audper = period;
 	amiga_audio_period = period;
-
-	AmiSetTreble(50);  /* recommended for newer amiga models */
 }
 
 
@@ -453,6 +486,7 @@
 		ch1 = start;
 	}
 
+	disable_heartbeat();
 	custom.aud[0].audvol = dmasound.volume_left;
 	custom.aud[1].audvol = dmasound.volume_right;
 	if (dmasound.hard.size == 8) {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_q40.c linux/drivers/sound/dmasound/dmasound_q40.c
--- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_q40.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/dmasound/dmasound_q40.c	Tue Apr 25 17:58:46 2000
@@ -1,10 +1,10 @@
 
 /*
- *  linux/drivers/sound/dmasound_q40.c
+ *  linux/drivers/sound/dmasound/dmasound_q40.c
  *
  *  Q40 DMA Sound Driver
  *
- *  See linux/drivers/sound/dmasound_core.c for copyright and credits
+ *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
  */
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/8010.h linux/drivers/sound/emu10k1/8010.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/8010.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/8010.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,662 @@
+/*
+ **********************************************************************
+ *     8010.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date		    Author	    Summary of changes
+ *     ----		    ------	    ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox	    Cleaned of 8bit chars, DOS
+ *					    line endings
+ *     December 8, 1999     Jon Taylor	    Added lots of new register info
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ *
+ **********************************************************************
+ */
+
+
+#ifndef _8010_H
+#define _8010_H
+
+/* ------------------- DEFINES -------------------- */
+
+#define EMUPAGESIZE	4096		/* don't change */
+#define RESERVED	0
+#define NUM_G		64		/* use all channels */
+#define NUM_FXSENDS	4		/* don't change */
+#define MAXPAGES        (32768 * NUM_G / EMUPAGESIZE)      /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */
+
+#define TMEMSIZE	256*1024
+#define TMEMSIZEREG	4
+
+#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL))
+
+/************************************************************************************************/
+/* PCI function 0 registers, address = <val> + PCIBASE0						*/
+/************************************************************************************************/
+
+#define PTR			0x00		/* Indexed register set pointer register	*/
+						/* NOTE: The CHANNELNUM and ADDRESS words can	*/
+						/* be modified independently of each other.	*/
+#define PTR_CHANNELNUM_MASK	0x0000003f	/* For each per-channel register, indicates the	*/
+						/* channel number of the register to be		*/
+						/* accessed.  For non per-channel registers the	*/
+						/* value should be set to zero.			*/
+#define PTR_ADDRESS_MASK	0x07ff0000	/* Register index				*/
+
+#define DATA			0x04		/* Indexed register set data register		*/
+
+#define IPR			0x08		/* Global interrupt pending register		*/
+						/* Clear pending interrupts by writing a 1 to	*/
+						/* the relevant bits and zero to the other bits	*/
+#define IPR_SAMPLERATETRACKER	0x01000000	/* Sample rate tracker lock status change	*/
+#define IPR_FXDSP		0x00800000	/* Enable FX DSP interrupts			*/
+#define IPR_FORCEINT		0x00400000	/* Force Sound Blaster interrupt		*/
+#define IPR_PCIERROR		0x00200000	/* PCI bus error				*/
+#define IPR_VOLINCR		0x00100000	/* Volume increment button pressed		*/
+#define IPR_VOLDECR		0x00080000	/* Volume decrement button pressed		*/
+#define IPR_MUTE		0x00040000	/* Mute button pressed				*/
+#define IPR_MICBUFFULL		0x00020000	/* Microphone buffer full			*/
+#define IPR_MICBUFHALFFULL	0x00010000	/* Microphone buffer half full			*/
+#define IPR_ADCBUFFULL		0x00008000	/* ADC buffer full				*/
+#define IPR_ADCBUFHALFFULL	0x00004000	/* ADC buffer half full				*/
+#define IPR_EFXBUFFULL		0x00002000	/* Effects buffer full				*/
+#define IPR_EFXBUFHALFFULL	0x00001000	/* Effects buffer half full			*/
+#define IPR_GPSPDIFSTATUSCHANGE	0x00000800	/* GPSPDIF channel status change		*/
+#define IPR_CDROMSTATUSCHANGE	0x00000400	/* CD-ROM channel status change			*/
+#define IPR_INTERVALTIMER	0x00000200	/* Interval timer terminal count		*/
+#define IPR_MIDITRANSBUFEMPTY	0x00000100	/* MIDI UART transmit buffer empty		*/
+#define IPR_MIDIRECVBUFEMPTY	0x00000080	/* MIDI UART receive buffer empty		*/
+#define IPR_CHANNELLOOP		0x00000040	/* One or more channel loop interrupts pending	*/
+#define IPR_CHANNELNUMBERMASK	0x0000003f	/* When IPR_CHANNELLOOP is set, indicates the	*/
+						/* Highest set channel in CLIPL or CLIPH.  When	*/
+						/* IP is written with CL set, the bit in CLIPL	*/
+						/* or CLIPH corresponding to the CIN value 	*/
+						/* written will be cleared.			*/
+
+#define INTE			0x0c		/* Interrupt enable register			*/
+#define INTE_VIRTUALSB_MASK	0xc0000000	/* Virtual Soundblaster I/O port capture	*/
+#define INTE_VIRTUALSB_220	0x00000000	/* Capture at I/O base address 0x220-0x22f	*/
+#define INTE_VIRTUALSB_240	0x40000000	/* Capture at I/O base address 0x240		*/
+#define INTE_VIRTUALSB_260	0x80000000	/* Capture at I/O base address 0x260		*/
+#define INTE_VIRTUALSB_280	0xc0000000	/* Capture at I/O base address 0x280		*/
+#define INTE_VIRTUALMPU_MASK	0x30000000	/* Virtual MPU I/O port capture			*/
+#define INTE_VIRTUALMPU_300	0x00000000	/* Capture at I/O base address 0x300-0x301	*/
+#define INTE_VIRTUALMPU_310	0x10000000	/* Capture at I/O base address 0x310		*/
+#define INTE_VIRTUALMPU_320	0x20000000	/* Capture at I/O base address 0x320		*/
+#define INTE_VIRTUALMPU_330	0x30000000	/* Capture at I/O base address 0x330		*/
+#define INTE_MASTERDMAENABLE	0x08000000	/* Master DMA emulation at 0x000-0x00f		*/
+#define INTE_SLAVEDMAENABLE	0x04000000	/* Slave DMA emulation at 0x0c0-0x0df		*/
+#define INTE_MASTERPICENABLE	0x02000000	/* Master PIC emulation at 0x020-0x021		*/
+#define INTE_SLAVEPICENABLE	0x01000000	/* Slave PIC emulation at 0x0a0-0x0a1		*/
+#define INTE_VSBENABLE		0x00800000	/* Enable virtual Soundblaster			*/
+#define INTE_ADLIBENABLE	0x00400000	/* Enable AdLib emulation at 0x388-0x38b	*/
+#define INTE_MPUENABLE		0x00200000	/* Enable virtual MPU				*/
+#define INTE_FORCEINT		0x00100000	/* Continuously assert INTAN			*/
+
+#define INTE_MRHANDENABLE	0x00080000	/* Enable the "Mr. Hand" logic			*/
+						/* NOTE: There is no reason to use this under	*/
+						/* Linux, and it will cause odd hardware 	*/
+						/* behavior and possibly random segfaults and	*/
+						/* lockups if enabled.				*/
+
+#define INTE_SAMPLERATETRACKER	0x00002000	/* Enable sample rate tracker interrupts	*/
+						/* NOTE: This bit must always be enabled       	*/
+#define INTE_FXDSPENABLE	0x00001000	/* Enable FX DSP interrupts			*/
+#define INTE_PCIERRORENABLE	0x00000800	/* Enable PCI bus error interrupts		*/
+#define INTE_VOLINCRENABLE	0x00000400	/* Enable volume increment button interrupts	*/
+#define INTE_VOLDECRENABLE	0x00000200	/* Enable volume decrement button interrupts	*/
+#define INTE_MUTEENABLE		0x00000100	/* Enable mute button interrupts		*/
+#define INTE_MICBUFENABLE	0x00000080	/* Enable microphone buffer interrupts		*/
+#define INTE_ADCBUFENABLE	0x00000040	/* Enable ADC buffer interrupts			*/
+#define INTE_EFXBUFENABLE	0x00000020	/* Enable Effects buffer interrupts		*/
+#define INTE_GPSPDIFENABLE	0x00000010	/* Enable GPSPDIF status interrupts		*/
+#define INTE_CDSPDIFENABLE	0x00000008	/* Enable CDSPDIF status interrupts		*/
+#define INTE_INTERVALTIMERENB	0x00000004	/* Enable interval timer interrupts		*/
+#define INTE_MIDITXENABLE	0x00000002	/* Enable MIDI transmit-buffer-empty interrupts	*/
+#define INTE_MIDIRXENABLE	0x00000001	/* Enable MIDI receive-buffer-empty interrupts	*/
+
+#define WC			0x10		/* Wall Clock register				*/
+#define WC_SAMPLECOUNTER_MASK	0x03FFFFC0	/* Sample periods elapsed since reset		*/
+#define WC_SAMPLECOUNTER	0x14060010
+#define WC_CURRENTCHANNEL	0x0000003F	/* Channel [0..63] currently being serviced	*/
+						/* NOTE: Each channel takes 1/64th of a sample	*/
+						/* period to be serviced.			*/
+
+#define HCFG			0x14		/* Hardware config register			*/
+						/* NOTE: There is no reason to use the legacy	*/
+						/* SoundBlaster emulation stuff described below	*/
+						/* under Linux, and all kinds of weird hardware	*/
+						/* behavior can result if you try.  Don't.	*/
+#define HCFG_LEGACYFUNC_MASK	0xe0000000	/* Legacy function number 			*/
+#define HCFG_LEGACYFUNC_MPU	0x00000000	/* Legacy MPU	 				*/
+#define HCFG_LEGACYFUNC_SB	0x40000000	/* Legacy SB					*/
+#define HCFG_LEGACYFUNC_AD	0x60000000	/* Legacy AD					*/
+#define HCFG_LEGACYFUNC_MPIC	0x80000000	/* Legacy MPIC					*/
+#define HCFG_LEGACYFUNC_MDMA	0xa0000000	/* Legacy MDMA					*/
+#define HCFG_LEGACYFUNC_SPCI	0xc0000000	/* Legacy SPCI					*/
+#define HCFG_LEGACYFUNC_SDMA	0xe0000000	/* Legacy SDMA					*/
+#define HCFG_IOCAPTUREADDR	0x1f000000	/* The 4 LSBs of the captured I/O address.	*/
+#define HCFG_LEGACYWRITE	0x00800000	/* 1 = write, 0 = read 				*/
+#define HCFG_LEGACYWORD		0x00400000	/* 1 = word, 0 = byte 				*/
+#define HCFG_LEGACYINT		0x00200000	/* 1 = legacy event captured. Write 1 to clear.	*/
+						/* NOTE: The rest of the bits in this register	*/
+						/* _are_ relevant under Linux.			*/
+#define HCFG_CODECFORMAT_MASK	0x00070000	/* CODEC format					*/
+#define HCFG_CODECFORMAT_AC97	0x00000000	/* AC97 CODEC format -- Primary Output		*/
+#define HCFG_CODECFORMAT_I2S	0x00010000	/* I2S CODEC format -- Secondary (Rear) Output	*/
+#define HCFG_GPINPUT0		0x00004000	/* External pin112				*/
+#define HCFG_GPINPUT1		0x00002000	/* External pin110				*/
+#define HCFG_GPOUTPUT_MASK	0x00001c00	/* External pins which may be controlled	*/
+#define HCFG_JOYENABLE      	0x00000200	/* Internal joystick enable    			*/
+#define HCFG_PHASETRACKENABLE	0x00000100	/* Phase tracking enable			*/
+						/* 1 = Force all 3 async digital inputs to use	*/
+						/* the same async sample rate tracker (ZVIDEO)	*/
+#define HCFG_AC3ENABLE_MASK	0x0x0000e0	/* AC3 async input control - Not implemented	*/
+#define HCFG_AC3ENABLE_ZVIDEO	0x00000080	/* Channels 0 and 1 replace ZVIDEO		*/
+#define HCFG_AC3ENABLE_CDSPDIF	0x00000040	/* Channels 0 and 1 replace CDSPDIF		*/
+#define HCFG_AUTOMUTE		0x00000010	/* When set, the async sample rate convertors	*/
+						/* will automatically mute their output when	*/
+						/* they are not rate-locked to the external	*/
+						/* async audio source  				*/
+#define HCFG_LOCKSOUNDCACHE	0x00000008	/* 1 = Cancel bustmaster accesses to soundcache */
+						/* NOTE: This should generally never be used.  	*/
+#define HCFG_LOCKTANKCACHE	0x00000004	/* 1 = Cancel bustmaster accesses to tankcache	*/
+						/* NOTE: This should generally never be used.  	*/
+#define HCFG_MUTEBUTTONENABLE	0x00000002	/* 1 = Master mute button sets AUDIOENABLE = 0.	*/
+						/* NOTE: This is a 'cheap' way to implement a	*/
+						/* master mute function on the mute button, and	*/
+						/* in general should not be used unless a more	*/
+						/* sophisticated master mute function has not	*/
+						/* been written.       				*/
+#define HCFG_AUDIOENABLE	0x00000001	/* 0 = CODECs transmit zero-valued samples	*/
+						/* Should be set to 1 when the EMU10K1 is	*/
+						/* completely initialized.			*/
+
+#define MUDATA			0x18		/* MPU401 data register (8 bits)       		*/
+
+#define MUCMD			0x19		/* MPU401 command register (8 bits)    		*/
+#define MUCMD_RESET		0xff		/* RESET command				*/
+#define MUCMD_ENTERUARTMODE	0x3f		/* Enter_UART_mode command			*/
+						/* NOTE: All other commands are ignored		*/
+
+#define MUSTAT			MUCMD		/* MPU401 status register (8 bits)     		*/
+#define MUSTAT_IRDYN		0x80		/* 0 = MIDI data or command ACK			*/
+#define MUSTAT_ORDYN		0x40		/* 0 = MUDATA can accept a command or data	*/
+
+#define TIMER			0x1a		/* Timer terminal count register		*/
+						/* NOTE: After the rate is changed, a maximum	*/
+						/* of 1024 sample periods should be allowed	*/
+						/* before the new rate is guaranteed accurate.	*/
+#define TIMER_RATE_MASK		0x000003ff	/* Timer interrupt rate in sample periods	*/
+						/* 0 == 1024 periods, [1..4] are not useful	*/
+#define TIMER_RATE		0x0a00001a
+
+#define AC97DATA		0x1c		/* AC97 register set data register (16 bit)	*/
+
+#define AC97ADDRESS		0x1e		/* AC97 register set address register (8 bit)	*/
+#define AC97ADDRESS_READY	0x80		/* Read-only bit, reflects CODEC READY signal	*/
+#define AC97ADDRESS_ADDRESS	0x7f		/* Address of indexed AC97 register		*/
+
+/************************************************************************************************/
+/* PCI function 1 registers, address = <val> + PCIBASE1						*/
+/************************************************************************************************/
+
+#define JOYSTICK1		0x00		/* Analog joystick port register		*/
+#define JOYSTICK2		0x01		/* Analog joystick port register		*/
+#define JOYSTICK3		0x02		/* Analog joystick port register		*/
+#define JOYSTICK4		0x03		/* Analog joystick port register		*/
+#define JOYSTICK5		0x04		/* Analog joystick port register		*/
+#define JOYSTICK6		0x05		/* Analog joystick port register		*/
+#define JOYSTICK7		0x06		/* Analog joystick port register		*/
+#define JOYSTICK8		0x07		/* Analog joystick port register		*/
+
+/* When writing, any write causes JOYSTICK_COMPARATOR output enable to be pulsed on write.	*/
+/* When reading, use these bitfields: */
+#define JOYSTICK_BUTTONS	0x0f		/* Joystick button data				*/
+#define JOYSTICK_COMPARATOR	0xf0		/* Joystick comparator data			*/
+
+
+/********************************************************************************************************/
+/* AC97 pointer-offset register set, accessed through the AC97ADDRESS and AC97DATA registers		*/
+/********************************************************************************************************/
+
+#define AC97_RESET		0x00
+#define AC97_MASTERVOLUME	0x02		/* Master volume					*/
+#define AC97_HEADPHONEVOLUME	0x04		/* Headphone volume					*/
+#define AC97_MASTERVOLUMEMONO	0x06		/* Mast volume mono					*/
+#define AC97_MASTERTONE		0x08
+#define AC97_PCBEEPVOLUME	0x0a		/* PC speaker system beep volume			*/
+#define AC97_PHONEVOLUME	0x0c
+#define AC97_MICVOLUME		0x0e
+#define AC97_LINEINVOLUME	0x10
+#define AC97_CDVOLUME		0x12
+#define AC97_VIDEOVOLUME	0x14
+#define AC97_AUXVOLUME		0x16
+#define AC97_PCMOUTVOLUME	0x18
+#define AC97_RECORDSELECT	0x1a
+#define AC97_RECORDGAIN		0x1c
+#define AC97_RECORDGAINMIC	0x1e
+#define AC97_GENERALPUPOSE	0x20
+#define AC97_3DCONTROL		0x22
+#define AC97_MODEMRATE		0x24
+#define AC97_POWERDOWN		0x26
+#define AC97_VENDORID1		0x7c
+#define AC97_VENDORID2		0x7e
+#define AC97_ZVIDEOVOLUME	0xec
+#define AC97_AC3VOLUME		0xed
+
+/********************************************************************************************************/
+/* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers			*/
+/********************************************************************************************************/
+
+#define CPF			0x00		/* Current pitch and fraction register			*/
+#define CPF_CURRENTPITCH_MASK	0xffff0000	/* Current pitch (linear, 0x4000 == unity pitch shift) 	*/
+#define CPF_CURRENTPITCH	0x10100000
+#define CPF_STEREO_MASK		0x00008000	/* 1 = Even channel interleave, odd channel locked	*/
+#define CPF_STOP_MASK		0x00004000	/* 1 = Current pitch forced to 0			*/
+#define CPF_FRACADDRESS_MASK	0x00003fff	/* Linear fractional address of the current channel	*/
+
+#define PTRX			0x01		/* Pitch target and send A/B amounts register		*/
+#define PTRX_PITCHTARGET_MASK	0xffff0000	/* Pitch target of specified channel			*/
+#define PTRX_PITCHTARGET	0x10100001
+#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00	/* Linear level of channel output sent to FX send bus A	*/
+#define PTRX_FXSENDAMOUNT_A	0x08080001
+#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff	/* Linear level of channel output sent to FX send bus B	*/
+#define PTRX_FXSENDAMOUNT_B	0x08000001
+
+#define CVCF			0x02		/* Current volume and filter cutoff register		*/
+#define CVCF_CURRENTVOL_MASK	0xffff0000	/* Current linear volume of specified channel		*/
+#define CVCF_CURRENTVOL		0x10100002
+#define CVCF_CURRENTFILTER_MASK	0x0000ffff	/* Current filter cutoff frequency of specified channel	*/
+#define CVCF_CURRENTFILTER	0x10000002
+
+#define VTFT			0x03		/* Volume target and filter cutoff target register	*/
+#define VTFT_VOLUMETARGET_MASK	0xffff0000	/* Volume target of specified channel			*/
+#define VTFT_FILTERTARGET_MASK	0x0000ffff	/* Filter cutoff target of specified channel		*/
+
+#define Z1			0x05		/* Filter delay memory 1 register			*/
+
+#define Z2			0x04		/* Filter delay memory 2 register			*/
+
+#define PSST			0x06		/* Send C amount and loop start address register	*/
+#define PSST_FXSENDAMOUNT_C_MASK 0xff000000	/* Linear level of channel output sent to FX send bus C	*/
+
+#define PSST_FXSENDAMOUNT_C	0x08180006
+
+#define PSST_LOOPSTARTADDR_MASK	0x00ffffff	/* Loop start address of the specified channel		*/
+#define PSST_LOOPSTARTADDR	0x18000006
+
+#define DSL			0x07		/* Send D amount and loop start address register	*/
+#define DSL_FXSENDAMOUNT_D_MASK	0xff000000	/* Linear level of channel output sent to FX send bus D	*/
+
+#define DSL_FXSENDAMOUNT_D	0x08180007
+
+#define DSL_LOOPENDADDR_MASK	0x00ffffff	/* Loop end address of the specified channel		*/
+#define DSL_LOOPENDADDR		0x18000007
+
+#define CCCA			0x08		/* Filter Q, interp. ROM, byte size, cur. addr register */
+#define CCCA_RESONANCE		0xf0000000	/* Lowpass filter resonance (Q) height			*/
+#define CCCA_INTERPROMMASK	0x0e000000	/* Selects passband of interpolation ROM		*/
+						/* 1 == full band, 7 == lowpass				*/
+						/* ROM 0 is used when pitch shifting downward or less	*/
+						/* then 3 semitones upward.  Increasingly higher ROM	*/
+						/* numbers are used, typically in steps of 3 semitones,	*/
+						/* as upward pitch shifting is performed.		*/
+#define CCCA_INTERPROM_0	0x00000000	/* Select interpolation ROM 0				*/
+#define CCCA_INTERPROM_1	0x02000000	/* Select interpolation ROM 1				*/
+#define CCCA_INTERPROM_2	0x04000000	/* Select interpolation ROM 2				*/
+#define CCCA_INTERPROM_3	0x06000000	/* Select interpolation ROM 3				*/
+#define CCCA_INTERPROM_4	0x08000000	/* Select interpolation ROM 4				*/
+#define CCCA_INTERPROM_5	0x0a000000	/* Select interpolation ROM 5				*/
+#define CCCA_INTERPROM_6	0x0c000000	/* Select interpolation ROM 6				*/
+#define CCCA_INTERPROM_7	0x0e000000	/* Select interpolation ROM 7				*/
+#define CCCA_8BITSELECT		0x01000000	/* 1 = Sound memory for this channel uses 8-bit samples	*/
+#define CCCA_CURRADDR_MASK	0x00ffffff	/* Current address of the selected channel		*/
+#define CCCA_CURRADDR		0x18000008
+
+#define CCR			0x09		/* Cache control register				*/
+#define CCR_CACHEINVALIDSIZE	0xfe000000	/* Number of invalid samples cache for this channel    	*/
+#define CCR_CACHELOOPFLAG	0x01000000	/* 1 = Cache has a loop service pending			*/
+#define CCR_INTERLEAVEDSAMPLES	0x00800000	/* 1 = A cache service will fetch interleaved samples	*/
+#define CCR_WORDSIZEDSAMPLES	0x00400000	/* 1 = A cache service will fetch word sized samples	*/
+#define CCR_READADDRESS_MASK	0x003f0000	/* Location of cache just beyond current cache service	*/
+#define CCR_LOOPINVALSIZE	0x0000fe00	/* Number of invalid samples in cache prior to loop	*/
+						/* NOTE: This is valid only if CACHELOOPFLAG is set	*/
+#define CCR_LOOPFLAG		0x00000100	/* Set for a single sample period when a loop occurs	*/
+#define CCR_CACHELOOPADDRHI	0x000000ff	/* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set	*/
+
+#define CLP			0x0a		/* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */
+						/* NOTE: This register is normally not used		*/
+#define CLP_CACHELOOPADDR	0x0000ffff	/* Cache loop address (DSL_LOOPSTARTADDR [0..15])	*/
+
+#define FXRT			0x0b		/* Effects send routing register			*/
+						/* NOTE: It is illegal to assign the same routing to	*/
+						/* two effects sends.					*/
+#define FXRT_CHANNELA		0x000f0000	/* Effects send bus number for channel's effects send A	*/
+#define FXRT_CHANNELB		0x00f00000	/* Effects send bus number for channel's effects send B	*/
+#define FXRT_CHANNELC		0x0f000000	/* Effects send bus number for channel's effects send C	*/
+#define FXRT_CHANNELD		0xf0000000	/* Effects send bus number for channel's effects send D	*/
+
+#define MAPA			0x0c		/* Cache map A						*/
+
+#define MAPB			0x0d		/* Cache map B						*/
+
+#define MAP_PTE_MASK		0xffffe000	/* The 19 MSBs of the PTE indexed by the PTI		*/
+#define MAP_PTI_MASK		0x00001fff	/* The 13 bit index to one of the 8192 PTE dwords      	*/
+
+#define ENVVOL			0x10		/* Volume envelope register				*/
+#define ENVVOL_MASK		0x0000ffff	/* Current value of volume envelope state variable	*/  
+						/* 0x8000-n == 666*n usec delay	       			*/
+
+#define ATKHLDV 		0x11		/* Volume envelope hold and attack register		*/
+#define ATKHLDV_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
+#define ATKHLDV_HOLDTIME_MASK	0x00007f00	/* Envelope hold time (127-n == n*88.2msec)		*/
+#define ATKHLDV_ATTACKTIME_MASK	0x0000007f	/* Envelope attack time, log encoded			*/
+						/* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec	*/
+
+#define DCYSUSV 		0x12		/* Volume envelope sustain and decay register		*/
+#define DCYSUSV_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
+#define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
+#define DCYSUSV_CHANNELENABLE_MASK 0x00000080	/* 1 = Inhibit envelope engine from writing values in	*/
+						/* this channel and from writing to pitch, filter and	*/
+						/* volume targets.					*/
+#define DCYSUSV_DECAYTIME_MASK	0x0000007f	/* Volume envelope decay time, log encoded     		*/
+						/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+
+#define LFOVAL1 		0x13		/* Modulation LFO value					*/
+#define LFOVAL_MASK		0x0000ffff	/* Current value of modulation LFO state variable	*/
+						/* 0x8000-n == 666*n usec delay				*/
+
+#define ENVVAL			0x14		/* Modulation envelope register				*/
+#define ENVVAL_MASK		0x0000ffff	/* Current value of modulation envelope state variable 	*/
+						/* 0x8000-n == 666*n usec delay				*/
+
+#define ATKHLDM			0x15		/* Modulation envelope hold and attack register		*/
+#define ATKHLDM_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
+#define ATKHLDM_HOLDTIME	0x00007f00	/* Envelope hold time (127-n == n*42msec)		*/
+#define ATKHLDM_ATTACKTIME	0x0000007f	/* Envelope attack time, log encoded			*/
+						/* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec		*/
+
+#define DCYSUSM			0x16		/* Modulation envelope decay and sustain register	*/
+#define DCYSUSM_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
+#define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
+#define DCYSUSM_DECAYTIME_MASK	0x0000007f	/* Envelope decay time, log encoded			*/
+						/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+
+#define LFOVAL2 		0x17		/* Vibrato LFO register					*/
+#define LFOVAL2_MASK		0x0000ffff	/* Current value of vibrato LFO state variable 		*/
+						/* 0x8000-n == 666*n usec delay				*/
+
+#define IP			0x18		/* Initial pitch register				*/
+#define IP_MASK			0x0000ffff	/* Exponential initial pitch shift			*/
+						/* 4 bits of octave, 12 bits of fractional octave	*/
+#define IP_UNITY		0x0000e000	/* Unity pitch shift					*/
+
+#define IFATN			0x19		/* Initial filter cutoff and attenuation register	*/
+#define IFATN_FILTERCUTOFF_MASK	0x0000ff00	/* Initial filter cutoff frequency in exponential units	*/
+						/* 6 most significant bits are semitones		*/
+						/* 2 least significant bits are fractions		*/
+#define IFATN_FILTERCUTOFF	0x08080019
+#define IFATN_ATTENUATION_MASK	0x000000ff	/* Initial attenuation in 0.375dB steps			*/
+#define IFATN_ATTENUATION	0x08000019
+
+
+#define PEFE			0x1a		/* Pitch envelope and filter envelope amount register	*/
+#define PEFE_PITCHAMOUNT_MASK	0x0000ff00	/* Pitch envlope amount					*/
+						/* Signed 2's complement, +/- one octave peak extremes	*/
+#define PEFE_PITCHAMOUNT	0x0808001a
+#define PEFE_FILTERAMOUNT_MASK	0x000000ff	/* Filter envlope amount				*/
+						/* Signed 2's complement, +/- six octaves peak extremes */
+#define PEFE_FILTERAMOUNT	0x0800001a
+#define FMMOD			0x1b		/* Vibrato/filter modulation from LFO register		*/
+#define FMMOD_MODVIBRATO	0x0000ff00	/* Vibrato LFO modulation depth				*/
+						/* Signed 2's complement, +/- one octave extremes	*/
+#define FMMOD_MOFILTER		0x000000ff	/* Filter LFO modulation depth				*/
+						/* Signed 2's complement, +/- three octave extremes	*/
+
+
+#define TREMFRQ 		0x1c		/* Tremolo amount and modulation LFO frequency register	*/
+#define TREMFRQ_DEPTH		0x0000ff00	/* Tremolo depth					*/
+						/* Signed 2's complement, with +/- 12dB extremes	*/
+
+#define FM2FRQ2 		0x1d		/* Vibrato amount and vibrato LFO frequency register	*/
+#define FM2FRQ2_DEPTH		0x0000ff00	/* Vibrato LFO vibrato depth				*/
+						/* Signed 2's complement, +/- one octave extremes	*/
+#define FM2FRQ2_FREQUENCY	0x000000ff	/* Vibrato LFO frequency				*/
+						/* 0.039Hz steps, maximum of 9.85 Hz.			*/
+
+#define TEMPENV 		0x1e		/* Tempory envelope register				*/
+#define TEMPENV_MASK		0x0000ffff	/* 16-bit value						*/
+						/* NOTE: All channels contain internal variables; do	*/
+						/* not write to these locations.			*/
+
+#define CD0			0x20		/* Cache data 0 register				*/
+#define CD1			0x21		/* Cache data 1 register				*/
+#define CD2			0x22		/* Cache data 2 register				*/
+#define CD3			0x23		/* Cache data 3 register				*/
+#define CD4			0x24		/* Cache data 4 register				*/
+#define CD5			0x25		/* Cache data 5 register				*/
+#define CD6			0x26		/* Cache data 6 register				*/
+#define CD7			0x27		/* Cache data 7 register				*/
+#define CD8			0x28		/* Cache data 8 register				*/
+#define CD9			0x29		/* Cache data 9 register				*/
+#define CDA			0x2a		/* Cache data A register				*/
+#define CDB			0x2b		/* Cache data B register				*/
+#define CDC			0x2c		/* Cache data C register				*/
+#define CDD			0x2d		/* Cache data D register				*/
+#define CDE			0x2e		/* Cache data E register				*/
+#define CDF			0x2f		/* Cache data F register				*/
+
+#define PTB			0x40		/* Page table base register				*/
+#define PTB_MASK		0xfffff000	/* Physical address of the page table in host memory	*/
+
+#define TCB			0x41		/* Tank cache base register    				*/
+#define TCB_MASK		0xfffff000	/* Physical address of the bottom of host based TRAM	*/
+
+#define ADCCR			0x42		/* ADC sample rate/stereo control register		*/
+#define ADCCR_RCHANENABLE	0x00000010	/* Enables right channel for writing to the host       	*/
+#define ADCCR_LCHANENABLE	0x00000008	/* Enables left channel for writing to the host		*/
+						/* NOTE: To guarantee phase coherency, both channels	*/
+						/* must be disabled prior to enabling both channels.	*/
+#define ADCCR_SAMPLERATE_MASK	0x00000007	/* Sample rate convertor output rate			*/
+#define ADCCR_SAMPLERATE_48	0x00000000	/* 48kHz sample rate					*/
+#define ADCCR_SAMPLERATE_44	0x00000001	/* 44.1kHz sample rate					*/
+#define ADCCR_SAMPLERATE_32	0x00000002	/* 32kHz sample rate					*/
+#define ADCCR_SAMPLERATE_24	0x00000003	/* 24kHz sample rate					*/
+#define ADCCR_SAMPLERATE_22	0x00000004	/* 22.05kHz sample rate					*/
+#define ADCCR_SAMPLERATE_16	0x00000005	/* 16kHz sample rate					*/
+#define ADCCR_SAMPLERATE_11	0x00000006	/* 11.025kHz sample rate				*/
+#define ADCCR_SAMPLERATE_8	0x00000007	/* 8kHz sample rate					*/
+
+#define FXWC			0x43		/* FX output write channels register			*/
+						/* When set, each bit enables the writing of the	*/
+						/* corresponding FX output channel into host memory	*/
+
+#define TCBS			0x44		/* Tank cache buffer size register			*/
+#define TCBS_MASK		0x00000007	/* Tank cache buffer size field				*/
+#define TCBS_BUFFSIZE_16K	0x00000000
+#define TCBS_BUFFSIZE_32K	0x00000001
+#define TCBS_BUFFSIZE_64K	0x00000002
+#define TCBS_BUFFSIZE_128K	0x00000003
+#define TCBS_BUFFSIZE_256K	0x00000004
+#define TCBS_BUFFSIZE_512K	0x00000005
+#define TCBS_BUFFSIZE_1024K	0x00000006
+#define TCBS_BUFFSIZE_2048K	0x00000007
+
+#define MICBA			0x45		/* AC97 microphone buffer address register		*/
+#define MICBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define ADCBA			0x46		/* ADC buffer address register				*/
+#define ADCBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define FXBA			0x47		/* FX Buffer Address */
+#define FXBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define MICBS			0x49		/* Microphone buffer size register			*/
+
+#define ADCBS			0x4a		/* ADC buffer size register				*/
+
+#define FXBS			0x4b		/* FX buffer size register				*/
+
+/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */
+#define ADCBS_BUFSIZE_NONE	0x00000000
+#define ADCBS_BUFSIZE_384	0x00000001
+#define ADCBS_BUFSIZE_448	0x00000002
+#define ADCBS_BUFSIZE_512	0x00000003
+#define ADCBS_BUFSIZE_640	0x00000004
+#define ADCBS_BUFSIZE_768	0x00000005
+#define ADCBS_BUFSIZE_896	0x00000006
+#define ADCBS_BUFSIZE_1024	0x00000007
+#define ADCBS_BUFSIZE_1280	0x00000008
+#define ADCBS_BUFSIZE_1536	0x00000009
+#define ADCBS_BUFSIZE_1792	0x0000000a
+#define ADCBS_BUFSIZE_2048	0x0000000b
+#define ADCBS_BUFSIZE_2560	0x0000000c
+#define ADCBS_BUFSIZE_3072	0x0000000d
+#define ADCBS_BUFSIZE_3584	0x0000000e
+#define ADCBS_BUFSIZE_4096	0x0000000f
+#define ADCBS_BUFSIZE_5120	0x00000010
+#define ADCBS_BUFSIZE_6144	0x00000011
+#define ADCBS_BUFSIZE_7168	0x00000012
+#define ADCBS_BUFSIZE_8192	0x00000013
+#define ADCBS_BUFSIZE_10240	0x00000014
+#define ADCBS_BUFSIZE_12288	0x00000015
+#define ADCBS_BUFSIZE_14366	0x00000016
+#define ADCBS_BUFSIZE_16384	0x00000017
+#define ADCBS_BUFSIZE_20480	0x00000018
+#define ADCBS_BUFSIZE_24576	0x00000019
+#define ADCBS_BUFSIZE_28672	0x0000001a
+#define ADCBS_BUFSIZE_32768	0x0000001b
+#define ADCBS_BUFSIZE_40960	0x0000001c
+#define ADCBS_BUFSIZE_49152	0x0000001d
+#define ADCBS_BUFSIZE_57344	0x0000001e
+#define ADCBS_BUFSIZE_65536	0x0000001f
+
+
+#define CDCS			0x50		/* CD-ROM digital channel status register	*/
+
+#define GPSCS			0x51		/* General Purpose SPDIF channel status register*/
+
+#define DBG			0x52		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+
+#define REG53			0x53		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+
+#define SPCS0			0x54		/* SPDIF output Channel Status 0 register	*/
+
+#define SPCS1			0x55		/* SPDIF output Channel Status 1 register	*/
+
+#define SPCS2			0x56		/* SPDIF output Channel Status 2 register	*/
+
+#define SPCS_CLKACCYMASK	0x30000000	/* Clock accuracy				*/
+#define SPCS_CLKACCY_1000PPM	0x00000000	/* 1000 parts per million			*/
+#define SPCS_CLKACCY_50PPM	0x10000000	/* 50 parts per million				*/
+#define SPCS_CLKACCY_VARIABLE	0x20000000	/* Variable accuracy				*/
+#define SPCS_SAMPLERATEMASK	0x0f000000	/* Sample rate					*/
+#define SPCS_SAMPLERATE_44	0x00000000	/* 44.1kHz sample rate				*/
+#define SPCS_SAMPLERATE_48	0x02000000	/* 48kHz sample rate				*/
+#define SPCS_SAMPLERATE_32	0x03000000	/* 32kHz sample rate				*/
+#define SPCS_CHANNELNUMMASK	0x00f00000	/* Channel number				*/
+#define SPCS_CHANNELNUM_UNSPEC	0x00000000	/* Unspecified channel number			*/
+#define SPCS_CHANNELNUM_LEFT	0x00100000	/* Left channel					*/
+#define SPCS_CHANNELNUM_RIGHT	0x00200000	/* Right channel				*/
+#define SPCS_SOURCENUMMASK	0x000f0000	/* Source number				*/
+#define SPCS_SOURCENUM_UNSPEC	0x00000000	/* Unspecified source number			*/
+#define SPCS_GENERATIONSTATUS	0x00008000	/* Originality flag (see IEC-958 spec)		*/
+#define SPCS_CATEGORYCODEMASK	0x00007f00	/* Category code (see IEC-958 spec)		*/
+#define SPCS_MODEMASK		0x000000c0	/* Mode (see IEC-958 spec)			*/
+#define SPCS_EMPHASISMASK	0x00000038	/* Emphasis					*/
+#define SPCS_EMPHASIS_NONE	0x00000000	/* No emphasis					*/
+#define SPCS_EMPHASIS_50_15	0x00000008	/* 50/15 usec 2 channel				*/
+#define SPCS_COPYRIGHT		0x00000004	/* Copyright asserted flag -- do not modify	*/
+#define SPCS_NOTAUDIODATA	0x00000002	/* 0 = Digital audio, 1 = not audio		*/
+#define SPCS_PROFESSIONAL	0x00000001	/* 0 = Consumer (IEC-958), 1 = pro (AES3-1992)	*/
+
+/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status      		*/
+#define CLIEL			0x58		/* Channel loop interrupt enable low register	*/
+
+#define CLIEH			0x59		/* Channel loop interrupt enable high register	*/
+
+#define CLIPL			0x5a		/* Channel loop interrupt pending low register	*/
+
+#define CLIPH			0x5b		/* Channel loop interrupt pending high register	*/
+
+#define SOLEL			0x5c		/* Stop on loop enable low register		*/
+
+#define SOLEH			0x5d		/* Stop on loop enable high register		*/
+
+#define SPBYPASS		0x5e		/* SPDIF BYPASS mode register			*/
+#define SPBYPASS_ENABLE		0x00000001	/* Enable SPDIF bypass mode			*/
+
+#define CDSRCS			0x60		/* CD-ROM Sample Rate Converter status register	*/
+
+#define GPSRCS			0x61		/* General Purpose SPDIF sample rate cvt status */
+
+#define ZVSRCS			0x62		/* ZVideo sample rate converter status		*/
+						/* NOTE: This one has no SPDIFLOCKED field	*/
+						/* Assumes sample lock				*/
+
+/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS.			*/
+#define SRCS_SPDIFLOCKED	0x02000000	/* SPDIF stream locked				*/
+#define SRCS_RATELOCKED		0x01000000	/* Sample rate locked				*/
+#define SRCS_ESTSAMPLERATE	0x0007ffff	/* Do not modify this field.			*/
+
+#define MICIDX                  0x63            /* Microphone recording buffer index register   */
+#define MICIDX_MASK             0x0000ffff      /* 16-bit value                                 */
+#define MICIDX_IDX		0x10000063
+
+#define ADCIDX			0x64		/* ADC recording buffer index register		*/
+#define ADCIDX_MASK		0x0000ffff	/* 16 bit index field				*/
+#define ADCIDX_IDX		0x10000064
+
+#define FXIDX			0x65		/* FX recording buffer index register		*/
+#define FXIDX_MASK		0x0000ffff	/* 16-bit value					*/
+#define FXIDX_IDX		0x10000065
+
+/* Each FX general purpose register is 32 bits in length, all bits are used			*/
+#define FXGPREGBASE		0x100		/* FX general purpose registers base       	*/
+
+/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is	*/
+/* decompressed back to 20 bits on a read.  There are a total of 160 locations, the last 32	*/
+/* locations are for external TRAM. 								*/
+#define TANKMEMDATAREGBASE	0x200		/* Tank memory data registers base     		*/
+#define TANKMEMDATAREG_MASK	0x000fffff	/* 20 bit tank audio data field			*/
+
+/* Combined address field and memory opcode or flag field.  160 locations, last 32 are external	*/
+#define TANKMEMADDRREGBASE	0x300		/* Tank memory address registers base		*/
+#define TANKMEMADDRREG_ADDR_MASK 0x000fffff	/* 20 bit tank address field			*/
+#define TANKMEMADDRREG_CLEAR	0x00800000	/* Clear tank memory				*/
+#define TANKMEMADDRREG_ALIGN	0x00400000	/* Align read or write relative to tank access	*/
+#define TANKMEMADDRREG_WRITE	0x00200000	/* Write to tank memory				*/
+#define TANKMEMADDRREG_READ	0x00100000	/* Read from tank memory			*/
+
+#define MICROCODEBASE		0x400		/* Microcode data base address			*/
+
+/* Each DSP microcode instruction is mapped into 2 doublewords 					*/
+/* NOTE: When writing, always write the LO doubleword first.  Reads can be in either order.	*/
+#define LOWORD_OPX_MASK		0x000ffc00	/* Instruction operand X			*/
+#define LOWORD_OPY_MASK		0x000003ff	/* Instruction operand Y			*/
+#define HIWORD_OPCODE_MASK	0x00f00000	/* Instruction opcode				*/
+#define HIWORD_RESULT_MASK	0x000ffc00	/* Instruction result				*/
+#define HIWORD_OPA_MASK		0x000003ff	/* Instruction operand A			*/
+
+#endif /* _8010_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/Makefile linux/drivers/sound/emu10k1/Makefile
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/Makefile	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,29 @@
+# Makefile for Creative Labs EMU10K1 
+#
+# 12 Apr 2000 Rui Sousa
+
+ifeq ($(CONFIG_SOUND_EMU10K1),y)
+    O_TARGET := emu10k1.o
+    O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \
+             emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
+             osutils.o recmgr.o timer.o voicemgr.o
+else
+  ifeq ($(CONFIG_SOUND_EMU10K1),m)
+    M_OBJS := emu10k1.o
+    O_TARGET := emu10k1.o
+    O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \
+             emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
+             osutils.o recmgr.o timer.o voicemgr.o
+  endif
+endif
+
+EXTRA_CFLAGS += -I.
+
+ifdef DEBUG
+    EXTRA_CFLAGS += -DEMU10K1_DEBUG
+endif
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/audio.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,1441 @@
+
+/*
+ **********************************************************************
+ *     audio.c -- /dev/dsp interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999	    Alan Cox        cleaned up types/leaks
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "cardwo.h"
+#include "cardwi.h"
+#include "recmgr.h"
+#include "audio.h"
+
+static void calculate_ofrag(struct woinst *);
+static void calculate_ifrag(struct wiinst *);
+
+/* Audio file operations */
+static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in;
+	ssize_t ret = 0;
+	unsigned long flags;
+
+	DPD(4, "emu10k1_audio_read(), buffer=%p, count=%x\n", buffer, (u32) count);
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+
+	spin_lock_irqsave(&wiinst->lock, flags);
+
+	if (wiinst->mapped) {
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		return -ENXIO;
+	}
+
+	if (!wiinst->wave_in) {
+		calculate_ifrag(wiinst);
+
+		while (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) {
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+
+			UP_INODE_SEM(&inode->i_sem);
+			interruptible_sleep_on(&wave_dev->card->open_wait);
+			DOWN_INODE_SEM(&inode->i_sem);
+
+			if (signal_pending(current))
+				return -ERESTARTSYS;
+
+			spin_lock_irqsave(&wiinst->lock, flags);
+		}
+	}
+
+	wave_in = wiinst->wave_in;
+
+	spin_unlock_irqrestore(&wiinst->lock, flags);
+
+	while (count > 0) {
+		u32 bytestocopy, dummy;
+
+		spin_lock_irqsave(&wiinst->lock, flags);
+
+		if ((wave_in->state != CARDWAVE_STATE_STARTED)
+		    && (wave_dev->enablebits & PCM_ENABLE_INPUT))
+			emu10k1_wavein_start(wave_dev);
+
+		emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
+
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+
+		DPD(4, "bytestocopy --> %x\n", bytestocopy);
+
+		if ((bytestocopy >= wiinst->fragment_size)
+		    || (bytestocopy >= count)) {
+			bytestocopy = min(bytestocopy, count);
+
+			emu10k1_wavein_xferdata(wiinst, (u8 *) buffer, &bytestocopy);
+
+			count -= bytestocopy;
+			buffer += bytestocopy;
+			ret += bytestocopy;
+		}
+
+		if (count > 0) {
+			if ((file->f_flags & O_NONBLOCK)
+			    || (!(wave_dev->enablebits & PCM_ENABLE_INPUT)))
+				return (ret ? ret : -EAGAIN);
+
+			UP_INODE_SEM(&inode->i_sem);
+			interruptible_sleep_on(&wiinst->wait_queue);
+			DOWN_INODE_SEM(&inode->i_sem);
+
+			if (signal_pending(current))
+				return (ret ? ret : -ERESTARTSYS);
+
+		}
+	}
+
+	DPD(4, "bytes copied -> %x\n", (u32) ret);
+
+	return ret;
+}
+
+static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out;
+	ssize_t ret;
+	unsigned long flags;
+
+	GET_INODE_STRUCT();
+
+	DPD(4, "emu10k1_audio_write(), buffer=%p, count=%x\n", buffer, (u32) count);
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+
+	spin_lock_irqsave(&woinst->lock, flags);
+
+	if (woinst->mapped) {
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		return -ENXIO;
+	}
+
+	if (!woinst->wave_out) {
+		calculate_ofrag(woinst);
+
+		while (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) {
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+
+			UP_INODE_SEM(&inode->i_sem);
+			interruptible_sleep_on(&wave_dev->card->open_wait);
+			DOWN_INODE_SEM(&inode->i_sem);
+
+			if (signal_pending(current))
+				return -ERESTARTSYS;
+
+			spin_lock_irqsave(&woinst->lock, flags);
+		}
+	}
+
+	wave_out = woinst->wave_out;
+
+	spin_unlock_irqrestore(&woinst->lock, flags);
+
+	ret = 0;
+	while (count > 0) {
+		u32 bytestocopy, pending, dummy;
+
+		spin_lock_irqsave(&woinst->lock, flags);
+
+		emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
+
+		spin_unlock_irqrestore(&woinst->lock, flags);
+
+		DPD(4, "bytestocopy --> %x\n", bytestocopy);
+
+		if ((bytestocopy >= woinst->fragment_size)
+		    || (bytestocopy >= count)) {
+
+			bytestocopy = min(bytestocopy, count);
+
+			emu10k1_waveout_xferdata(woinst, (u8 *) buffer, &bytestocopy);
+
+			count -= bytestocopy;
+			buffer += bytestocopy;
+			ret += bytestocopy;
+
+			spin_lock_irqsave(&woinst->lock, flags);
+			woinst->total_copied += bytestocopy;
+
+			if ((wave_out->state != CARDWAVE_STATE_STARTED)
+			    && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)
+			    && (woinst->total_copied >= woinst->fragment_size)) {
+
+				if (emu10k1_waveout_start(wave_dev) != CTSTATUS_SUCCESS) {
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					ERROR();
+					return -EFAULT;
+				}
+			}
+			spin_unlock_irqrestore(&woinst->lock, flags);
+		}
+
+		if (count > 0) {
+			if ((file->f_flags & O_NONBLOCK)
+			    || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT)))
+				return (ret ? ret : -EAGAIN);
+
+			UP_INODE_SEM(&inode->i_sem);
+			interruptible_sleep_on(&woinst->wait_queue);
+			DOWN_INODE_SEM(&inode->i_sem);
+
+			if (signal_pending(current))
+				return (ret ? ret : -ERESTARTSYS);
+		}
+	}
+
+	DPD(4, "bytes copied -> %x\n", (u32) ret);
+
+	return ret;
+}
+
+static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+	int val = 0;
+	struct woinst *woinst = NULL;
+	struct wave_out *wave_out = NULL;
+	struct wiinst *wiinst = NULL;
+	struct wave_in *wave_in = NULL;
+	u32 pending, bytestocopy, dummy;
+	unsigned long flags;
+
+	DPF(4, "emu10k1_audio_ioctl()\n");
+
+	if (file->f_mode & FMODE_WRITE) {
+		woinst = wave_dev->woinst;
+		spin_lock_irqsave(&woinst->lock, flags);
+		wave_out = woinst->wave_out;
+		spin_unlock_irqrestore(&woinst->lock, flags);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		wiinst = wave_dev->wiinst;
+		spin_lock_irqsave(&wiinst->lock, flags);
+		wave_in = wiinst->wave_in;
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+	}
+
+	switch (cmd) {
+	case OSS_GETVERSION:
+		DPF(2, "OSS_GETVERSION:\n");
+		return put_user(SOUND_VERSION, (int *) arg);
+
+	case SNDCTL_DSP_RESET:
+		DPF(2, "SNDCTL_DSP_RESET:\n");
+		wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;
+
+		if (file->f_mode & FMODE_WRITE) {
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out)
+				emu10k1_waveout_close(wave_dev);
+
+			woinst->total_copied = 0;
+			woinst->total_played = 0;
+			woinst->blocks = 0;
+			woinst->curpos = 0;
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+				emu10k1_wavein_close(wave_dev);
+
+			wiinst->total_recorded = 0;
+			wiinst->blocks = 0;
+			wiinst->curpos = 0;
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+		}
+
+		break;
+
+	case SNDCTL_DSP_SYNC:
+		DPF(2, "SNDCTL_DSP_SYNC:\n");
+
+		if (file->f_mode & FMODE_WRITE) {
+
+			if (wave_out) {
+				spin_lock_irqsave(&woinst->lock, flags);
+
+				if (wave_out->state == CARDWAVE_STATE_STARTED)
+					while ((woinst->total_played < woinst->total_copied)
+					       && !signal_pending(current)) {
+						spin_unlock_irqrestore(&woinst->lock, flags);
+						interruptible_sleep_on(&woinst->wait_queue);
+						spin_lock_irqsave(&woinst->lock, flags);
+					}
+
+				emu10k1_waveout_close(wave_dev);
+				woinst->total_copied = 0;
+				woinst->total_played = 0;
+				woinst->blocks = 0;
+				woinst->curpos = 0;
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+			}
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+				emu10k1_wavein_close(wave_dev);
+
+			wiinst->total_recorded = 0;
+			wiinst->blocks = 0;
+			wiinst->curpos = 0;
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+		}
+
+		break;
+
+	case SNDCTL_DSP_SETDUPLEX:
+		DPF(2, "SNDCTL_DSP_SETDUPLEX:\n");
+		break;
+
+	case SNDCTL_DSP_GETCAPS:
+		DPF(2, "SNDCTL_DSP_GETCAPS:\n");
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg);
+
+	case SNDCTL_DSP_SPEED:
+		DPF(2, "SNDCTL_DSP_SPEED:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, "val is %d\n", val);
+
+		if (val >= 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				spin_lock_irqsave(&woinst->lock, flags);
+
+				woinst->wave_fmt.samplingrate = val;
+
+				if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
+
+				val = woinst->wave_fmt.samplingrate;
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+
+				DPD(2, "set playback sampling rate -> %d\n", val);
+			}
+
+			if (file->f_mode & FMODE_READ) {
+				spin_lock_irqsave(&wiinst->lock, flags);
+
+				wiinst->wave_fmt.samplingrate = val;
+
+				if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
+
+				val = wiinst->wave_fmt.samplingrate;
+
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				DPD(2, "set recording sampling rate -> %d\n", val);
+			}
+
+			return put_user(val, (int *) arg);
+		} else {
+			if (file->f_mode & FMODE_READ)
+				val = wiinst->wave_fmt.samplingrate;
+			else if (file->f_mode & FMODE_WRITE)
+				val = woinst->wave_fmt.samplingrate;
+
+			return put_user(val, (int *) arg);
+		}
+		break;
+
+	case SNDCTL_DSP_STEREO:
+		DPF(2, "SNDCTL_DSP_STEREO:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, " val is %d\n", val);
+
+		if (file->f_mode & FMODE_WRITE) {
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			woinst->wave_fmt.channels = val ? 2 : 1;
+
+			if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+				return -EINVAL;
+
+			val = woinst->wave_fmt.channels - 1;
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			DPD(2, "set playback stereo -> %d\n", val);
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			wiinst->wave_fmt.channels = val ? 2 : 1;
+
+			if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+				return -EINVAL;
+
+			val = wiinst->wave_fmt.channels - 1;
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+			DPD(2, "set recording stereo -> %d\n", val);
+		}
+
+		return put_user(val, (int *) arg);
+
+		break;
+
+	case SNDCTL_DSP_CHANNELS:
+		DPF(2, "SNDCTL_DSP_CHANNELS:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, " val is %d\n", val);
+
+		if (val != 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				spin_lock_irqsave(&woinst->lock, flags);
+
+				woinst->wave_fmt.channels = val;
+
+				if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
+
+				val = woinst->wave_fmt.channels;
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				DPD(2, "set playback number of channels -> %d\n", val);
+			}
+
+			if (file->f_mode & FMODE_READ) {
+				spin_lock_irqsave(&wiinst->lock, flags);
+
+				wiinst->wave_fmt.channels = val;
+
+				if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
+
+				val = wiinst->wave_fmt.channels;
+
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+				DPD(2, "set recording number of channels -> %d\n", val);
+			}
+
+			return put_user(val, (int *) arg);
+		} else {
+			if (file->f_mode & FMODE_READ)
+				val = wiinst->wave_fmt.channels;
+			else if (file->f_mode & FMODE_WRITE)
+				val = woinst->wave_fmt.channels;
+
+			return put_user(val, (int *) arg);
+		}
+		break;
+
+	case SNDCTL_DSP_GETFMTS:
+		DPF(2, "SNDCTL_DSP_GETFMTS:\n");
+
+		if (file->f_mode & FMODE_READ)
+			val = AFMT_S16_LE;
+		else if (file->f_mode & FMODE_WRITE)
+			val = AFMT_S16_LE | AFMT_U8;
+
+		return put_user(val, (int *) arg);
+
+	case SNDCTL_DSP_SETFMT:	/* Same as SNDCTL_DSP_SAMPLESIZE */
+		DPF(2, "SNDCTL_DSP_SETFMT:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, " val is %d\n", val);
+
+		if (val != AFMT_QUERY) {
+			if (file->f_mode & FMODE_WRITE) {
+				spin_lock_irqsave(&woinst->lock, flags);
+
+				woinst->wave_fmt.bitsperchannel = val;
+
+				if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
+
+				val = woinst->wave_fmt.bitsperchannel;
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				DPD(2, "set playback sample size -> %d\n", val);
+			}
+
+			if (file->f_mode & FMODE_READ) {
+				spin_lock_irqsave(&wiinst->lock, flags);
+
+				wiinst->wave_fmt.bitsperchannel = val;
+
+				if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
+
+				val = wiinst->wave_fmt.bitsperchannel;
+
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+				DPD(2, "set recording sample size -> %d\n", val);
+			}
+
+			return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
+		} else {
+			if (file->f_mode & FMODE_READ)
+				val = wiinst->wave_fmt.bitsperchannel;
+			else if (file->f_mode & FMODE_WRITE)
+				val = woinst->wave_fmt.bitsperchannel;
+
+			return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
+		}
+		break;
+
+	case SOUND_PCM_READ_BITS:
+
+		if (file->f_mode & FMODE_READ)
+			val = wiinst->wave_fmt.bitsperchannel;
+		else if (file->f_mode & FMODE_WRITE)
+			val = woinst->wave_fmt.bitsperchannel;
+
+		return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
+
+	case SOUND_PCM_READ_RATE:
+
+		if (file->f_mode & FMODE_READ)
+			val = wiinst->wave_fmt.samplingrate;
+		else if (file->f_mode & FMODE_WRITE)
+			val = woinst->wave_fmt.samplingrate;
+
+		return put_user(val, (int *) arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+
+		if (file->f_mode & FMODE_READ)
+			val = wiinst->wave_fmt.channels;
+		else if (file->f_mode & FMODE_WRITE)
+			val = woinst->wave_fmt.channels;
+
+		return put_user(val, (int *) arg);
+
+	case SOUND_PCM_WRITE_FILTER:
+		DPF(2, "SOUND_PCM_WRITE_FILTER: not implemented\n");
+		break;
+
+	case SOUND_PCM_READ_FILTER:
+		DPF(2, "SOUND_PCM_READ_FILTER: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_SETSYNCRO:
+		DPF(2, "SNDCTL_DSP_SETSYNCRO: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_GETTRIGGER:
+		DPF(2, "SNDCTL_DSP_GETTRIGGER:\n");
+
+		if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT))
+			val |= PCM_ENABLE_OUTPUT;
+		if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT))
+			val |= PCM_ENABLE_INPUT;
+
+		return put_user(val, (int *) arg);
+
+	case SNDCTL_DSP_SETTRIGGER:
+		DPF(2, "SNDCTL_DSP_SETTRIGGER:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+
+		if (file->f_mode & FMODE_WRITE) {
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (val & PCM_ENABLE_OUTPUT) {
+				wave_dev->enablebits |= PCM_ENABLE_OUTPUT;
+				if (wave_out)
+					emu10k1_waveout_start(wave_dev);
+			} else {
+				wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT;
+				if (wave_out)
+					emu10k1_waveout_stop(wave_dev);
+			}
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (val & PCM_ENABLE_INPUT) {
+				wave_dev->enablebits |= PCM_ENABLE_INPUT;
+				if (wave_in)
+					emu10k1_wavein_start(wave_dev);
+			} else {
+				wave_dev->enablebits &= ~PCM_ENABLE_INPUT;
+				if (wave_in)
+					emu10k1_wavein_stop(wave_dev);
+			}
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+		}
+		break;
+
+	case SNDCTL_DSP_GETOSPACE:
+		{
+			audio_buf_info info;
+
+			DPF(4, "SNDCTL_DSP_GETOSPACE:\n");
+
+			if (!(file->f_mode & FMODE_WRITE))
+				return -EINVAL;
+
+			if (wave_out) {
+				spin_lock_irqsave(&woinst->lock, flags);
+				emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
+				spin_unlock_irqrestore(&woinst->lock, flags);
+
+				info.bytes = bytestocopy;
+			} else {
+				spin_lock_irqsave(&woinst->lock, flags);
+				calculate_ofrag(woinst);
+				spin_unlock_irqrestore(&woinst->lock, flags);
+
+				info.bytes = woinst->numfrags * woinst->fragment_size;
+			}
+
+			info.fragstotal = woinst->numfrags;
+			info.fragments = info.bytes / woinst->fragment_size;
+			info.fragsize = woinst->fragment_size;
+
+			if (copy_to_user((int *) arg, &info, sizeof(info)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_GETISPACE:
+		{
+			audio_buf_info info;
+
+			DPF(4, "SNDCTL_DSP_GETISPACE:\n");
+
+			if (!(file->f_mode & FMODE_READ))
+				return -EINVAL;
+
+			if (wave_in) {
+				spin_lock_irqsave(&wiinst->lock, flags);
+				emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				info.bytes = bytestocopy;
+			} else {
+				spin_lock_irqsave(&wiinst->lock, flags);
+				calculate_ifrag(wiinst);
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				info.bytes = 0;
+			}
+
+			info.fragstotal = wiinst->numfrags;
+			info.fragments = info.bytes / wiinst->fragment_size;
+			info.fragsize = wiinst->fragment_size;
+
+			if (copy_to_user((int *) arg, &info, sizeof(info)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_NONBLOCK:
+		DPF(2, "SNDCTL_DSP_NONBLOCK:\n");
+
+		file->f_flags |= O_NONBLOCK;
+		break;
+
+	case SNDCTL_DSP_GETODELAY:
+		DPF(4, "SNDCTL_DSP_GETODELAY:\n");
+
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+
+		if (wave_out) {
+			spin_lock_irqsave(&woinst->lock, flags);
+			emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			val = pending;
+		} else
+			val = 0;
+
+		return put_user(val, (int *) arg);
+
+	case SNDCTL_DSP_GETIPTR:
+		{
+			count_info cinfo;
+
+			DPF(4, "SNDCTL_DSP_GETIPTR: \n");
+
+			if (!(file->f_mode & FMODE_READ))
+				return -EINVAL;
+
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in) {
+				emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, (u32 *) & cinfo.ptr);
+				cinfo.bytes =
+				    cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags);
+				cinfo.blocks = cinfo.bytes / wiinst->fragment_size - wiinst->blocks;
+				wiinst->blocks = cinfo.bytes / wiinst->fragment_size;
+			} else {
+				cinfo.ptr = 0;
+				cinfo.bytes = 0;
+				cinfo.blocks = 0;
+				wiinst->blocks = 0;
+			}
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+
+			if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_GETOPTR:
+		{
+			count_info cinfo;
+
+			DPF(4, "SNDCTL_DSP_GETOPTR:\n");
+
+			if (!(file->f_mode & FMODE_WRITE))
+				return -EINVAL;
+
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out) {
+				emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, (u32 *) & cinfo.ptr);
+				cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags);
+				cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->blocks;
+				woinst->blocks = cinfo.bytes / woinst->fragment_size;
+			} else {
+				cinfo.ptr = 0;
+				cinfo.bytes = 0;
+				cinfo.blocks = 0;
+				woinst->blocks = 0;
+			}
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n");
+
+		if (file->f_mode & FMODE_WRITE) {
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			calculate_ofrag(woinst);
+			val = woinst->fragment_size;
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			calculate_ifrag(wiinst);
+			val = wiinst->fragment_size;
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+		}
+
+		return put_user(val, (int *) arg);
+
+		break;
+
+	case SNDCTL_DSP_POST:
+		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		DPF(2, "SNDCTL_DSP_SUBDIVIDE: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+
+		DPD(2, "val is %x\n", val);
+
+		if (val == 0)
+			return -EIO;
+
+		if (file->f_mode & FMODE_WRITE) {
+			if (wave_out)
+				return -EINVAL;	/* too late to change */
+
+			woinst->ossfragshift = val & 0xffff;
+			woinst->numfrags = (val >> 16) & 0xffff;
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			if (wave_in)
+				return -EINVAL;	/* too late to change */
+
+			wiinst->ossfragshift = val & 0xffff;
+			wiinst->numfrags = (val >> 16) & 0xffff;
+		}
+
+		break;
+
+	case SNDCTL_COPR_LOAD:
+		{
+			copr_buffer buf;
+			u32 i;
+
+			DPF(2, "SNDCTL_COPR_LOAD:\n");
+
+			if (copy_from_user(&buf, (copr_buffer *) arg, sizeof(buf)))
+				return -EFAULT;
+
+			if ((buf.command != 1) && (buf.command != 2))
+				return -EINVAL;
+
+			if (((buf.offs < 0x100) && (buf.command == 2))
+			    || (buf.offs < 0x000)
+			    || (buf.offs + buf.len > 0x800) || (buf.len > 1000))
+				return -EINVAL;
+
+			if (buf.command == 1) {
+				for (i = 0; i < buf.len; i++)
+
+					((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0);
+				if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf)))
+					return -EFAULT;
+			} else {
+				for (i = 0; i < buf.len; i++)
+					sblive_writeptr(wave_dev->card, buf.offs + i, 0, ((u32 *) buf.data)[i]);
+			}
+			break;
+		}
+
+	default:		/* Default is unrecognized command */
+		DPD(2, "default: %x\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+
+	DPF(2, "emu10k1_audio_mmap()\n");
+
+	if (vma_get_pgoff(vma) != 0)
+		return -ENXIO;
+
+	if (vma->vm_flags & VM_WRITE) {
+		struct woinst *woinst = wave_dev->woinst;
+		struct wave_out *wave_out;
+		u32 size;
+		unsigned long flags;
+		int i;
+
+		spin_lock_irqsave(&woinst->lock, flags);
+
+		wave_out = woinst->wave_out;
+
+		if (!wave_out) {
+			calculate_ofrag(woinst);
+
+			if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) {
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				ERROR();
+				return -EINVAL;
+			}
+
+			wave_out = woinst->wave_out;
+
+			/* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */
+			for (i = 0; i < wave_out->wavexferbuf->numpages; i++)
+				set_bit(PG_reserved, &mem_map[MAP_NR(wave_out->pagetable[i])].flags);
+		}
+
+		size = vma->vm_end - vma->vm_start;
+
+		if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) {
+			spin_unlock_irqrestore(&woinst->lock, flags);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < wave_out->wavexferbuf->numpages; i++) {
+			if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) {
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				return -EAGAIN;
+			}
+		}
+
+		woinst->mapped = 1;
+
+		spin_unlock_irqrestore(&woinst->lock, flags);
+	}
+
+	if (vma->vm_flags & VM_READ) {
+		struct wiinst *wiinst = wave_dev->wiinst;
+		unsigned long flags;
+
+		spin_lock_irqsave(&wiinst->lock, flags);
+		wiinst->mapped = 1;
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+	}
+
+	return 0;
+}
+
+static int emu10k1_audio_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct emu10k1_card *card;
+	struct list_head *entry;
+	struct emu10k1_wavedevice *wave_dev;
+
+	DPF(2, "emu10k1_audio_open()\n");
+
+	/* Check for correct device to open */
+
+	list_for_each(entry, &emu10k1_devs) {
+		card = list_entry(entry, struct emu10k1_card, list);
+
+		if (card->audio1_num == minor || card->audio2_num == minor)
+			break;
+	}
+
+	if (entry == &emu10k1_devs)
+		return -ENODEV;
+
+	MOD_INC_USE_COUNT;
+
+	if ((wave_dev = (struct emu10k1_wavedevice *)
+	     kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL)) == NULL) {
+		ERROR();
+		MOD_DEC_USE_COUNT;
+		return -EINVAL;
+	}
+
+	wave_dev->card = card;
+	wave_dev->wiinst = NULL;
+	wave_dev->woinst = NULL;
+	wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;	/* Default */
+
+	if (file->f_mode & FMODE_WRITE) {
+		struct woinst *woinst;
+
+		if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) {
+			ERROR();
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+
+		woinst->wave_fmt.samplingrate = 8000;
+		woinst->wave_fmt.bitsperchannel = 8;
+		woinst->wave_fmt.channels = 1;
+		woinst->ossfragshift = 0;
+		woinst->fragment_size = 0;
+		woinst->numfrags = 0;
+		woinst->device = (card->audio2_num == minor);
+		woinst->wave_out = NULL;
+
+		init_waitqueue_head(&woinst->wait_queue);
+
+		woinst->mapped = 0;
+		woinst->total_copied = 0;
+		woinst->total_played = 0;
+		woinst->blocks = 0;
+		woinst->curpos = 0;
+		woinst->lock = SPIN_LOCK_UNLOCKED;
+		wave_dev->woinst = woinst;
+
+#ifdef PRIVATE_PCM_VOLUME
+		{
+			int i;
+			int j = -1;
+
+			/*
+			 * find out if we've already been in this table
+			 * xmms reopens dsp on every move of slider
+			 * this way we keep the same local pcm for such
+			 * process
+			 */
+			for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+				if (sblive_pcm_volume[i].files == current->files)
+					break;
+				// here we should select last used memeber
+				// improve me in case its not sufficient
+				if (j < 0 && !sblive_pcm_volume[i].opened)
+					j = i;
+			}
+			// current task not found
+			if (i == MAX_PCM_CHANNELS) {
+				// add new entry
+				if (j < 0)
+					printk("TOO MANY WRITTERS!!!\n");
+				i = (j >= 0) ? j : 0;
+				DPD(2, "new pcm private %p\n", current->files);
+				sblive_pcm_volume[i].files = current->files;
+				sblive_pcm_volume[i].mixer = 0x6464;	// max
+				sblive_pcm_volume[i].attn_l = 0;
+				sblive_pcm_volume[i].attn_r = 0;
+				sblive_pcm_volume[i].channel_l = NUM_G;
+				sblive_pcm_volume[i].channel_r = NUM_G;
+			}
+			sblive_pcm_volume[i].opened++;
+		}
+#endif
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		/* Recording */
+		struct wiinst *wiinst;
+
+		if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
+			ERROR();
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+
+		switch (card->wavein->recsrc) {
+		case WAVERECORD_AC97:
+			wiinst->wave_fmt.samplingrate = 8000;
+			wiinst->wave_fmt.bitsperchannel = 8;
+			wiinst->wave_fmt.channels = 1;
+			break;
+		case WAVERECORD_MIC:
+			wiinst->wave_fmt.samplingrate = 8000;
+			wiinst->wave_fmt.bitsperchannel = 8;
+			wiinst->wave_fmt.channels = 1;
+			break;
+		case WAVERECORD_FX:
+			wiinst->wave_fmt.samplingrate = 48000;
+			wiinst->wave_fmt.bitsperchannel = 16;
+			wiinst->wave_fmt.channels = 2;
+			break;
+		default:
+			break;
+		}
+
+		wiinst->recsrc = card->wavein->recsrc;
+		wiinst->ossfragshift = 0;
+		wiinst->fragment_size = 0;
+		wiinst->numfrags = 0;
+		wiinst->wave_in = NULL;
+
+		init_waitqueue_head(&wiinst->wait_queue);
+
+		wiinst->mapped = 0;
+		wiinst->total_recorded = 0;
+		wiinst->blocks = 0;
+		wiinst->curpos = 0;
+		wiinst->lock = SPIN_LOCK_UNLOCKED;
+		wave_dev->wiinst = wiinst;
+	}
+
+	file->private_data = (void *) wave_dev;
+
+	return 0;		/* Success? */
+}
+
+static int emu10k1_audio_release(struct inode *inode, struct file *file)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+	struct emu10k1_card *card = wave_dev->card;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_audio_release()\n");
+
+	if (file->f_mode & FMODE_WRITE) {
+		struct woinst *woinst = wave_dev->woinst;
+		struct wave_out *wave_out;
+
+		spin_lock_irqsave(&woinst->lock, flags);
+
+		wave_out = woinst->wave_out;
+
+		if (wave_out) {
+			if ((wave_out->state == CARDWAVE_STATE_STARTED)
+			    && !(file->f_flags & O_NONBLOCK)) {
+				while (!signal_pending(current)
+				       && (woinst->total_played < woinst->total_copied)) {
+					DPF(4, "Buffer hasn't been totally played, sleep....\n");
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					interruptible_sleep_on(&woinst->wait_queue);
+					spin_lock_irqsave(&woinst->lock, flags);
+				}
+			}
+
+			if (woinst->mapped && wave_out->pagetable) {
+				int i;
+
+				/* Undo marking the pages as reserved */
+				for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++)
+					set_bit(PG_reserved, &mem_map[MAP_NR(woinst->wave_out->pagetable[i])].flags);
+			}
+
+			woinst->mapped = 0;
+			emu10k1_waveout_close(wave_dev);
+		}
+#ifdef PRIVATE_PCM_VOLUME
+		{
+			int i;
+
+			/* mark as closed
+			 * NOTE: structure remains unchanged for next reopen */
+			for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+				if (sblive_pcm_volume[i].files == current->files) {
+					sblive_pcm_volume[i].opened--;
+					break;
+				}
+			}
+		}
+#endif
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		kfree(wave_dev->woinst);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		struct wiinst *wiinst = wave_dev->wiinst;
+		struct wave_in *wave_in;
+
+		spin_lock_irqsave(&wiinst->lock, flags);
+
+		wave_in = wiinst->wave_in;
+
+		if (wave_in) {
+			wiinst->mapped = 0;
+			emu10k1_wavein_close(wave_dev);
+		}
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		kfree(wave_dev->wiinst);
+	}
+
+	kfree(wave_dev);
+
+	wake_up_interruptible(&card->open_wait);
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	unsigned int mask = 0;
+	u32 bytestocopy, pending, dummy;
+	unsigned long flags;
+
+	DPF(4, "emu10k1_audio_poll()\n");
+
+	if (file->f_mode & FMODE_WRITE)
+		poll_wait(file, &woinst->wait_queue, wait);
+
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &wiinst->wait_queue, wait);
+
+	if (file->f_mode & FMODE_WRITE) {
+		struct wave_out *wave_out;
+
+		spin_lock_irqsave(&woinst->lock, flags);
+
+		wave_out = woinst->wave_out;
+
+		if (wave_out) {
+
+			emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
+
+			if (bytestocopy >= woinst->fragment_size)
+				mask |= POLLOUT | POLLWRNORM;
+		} else
+			mask |= POLLOUT | POLLWRNORM;
+
+		spin_unlock_irqrestore(&woinst->lock, flags);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		struct wave_in *wave_in;
+
+		spin_lock_irqsave(&wiinst->lock, flags);
+
+		wave_in = wiinst->wave_in;
+
+		if (!wave_in) {
+			calculate_ifrag(wiinst);
+			if (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) {
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+				return (mask |= POLLERR);
+			}
+
+			wave_in = wiinst->wave_in;
+		}
+
+		if (wave_in->state != CARDWAVE_STATE_STARTED) {
+			wave_dev->enablebits |= PCM_ENABLE_INPUT;
+			emu10k1_wavein_start(wave_dev);
+		}
+
+		emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
+
+		if (bytestocopy >= wiinst->fragment_size)
+			mask |= POLLIN | POLLRDNORM;
+
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+	}
+
+	return mask;
+}
+
+static void calculate_ofrag(struct woinst *woinst)
+{
+	u32 fragsize, bytespersec;
+
+	if (woinst->fragment_size)
+		return;
+
+	bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitsperchannel >> 3) * woinst->wave_fmt.samplingrate;
+
+	if (!woinst->ossfragshift) {
+		fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1;
+
+		while (fragsize) {
+			fragsize >>= 1;
+			woinst->ossfragshift++;
+		}
+	}
+
+	if (woinst->ossfragshift < WAVEOUT_MINFRAGSHIFT)
+		woinst->ossfragshift = WAVEOUT_MINFRAGSHIFT;
+
+	woinst->fragment_size = 1 << woinst->ossfragshift;
+
+	if (!woinst->numfrags) {
+		u32 numfrags;
+
+		numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN) / (woinst->fragment_size * 1000) - 1;
+
+		woinst->numfrags = 1;
+
+		while (numfrags) {
+			numfrags >>= 1;
+			woinst->numfrags <<= 1;
+		}
+	}
+
+	if (woinst->numfrags < MINFRAGS)
+		woinst->numfrags = MINFRAGS;
+
+	if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE) {
+		woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size;
+
+		if (woinst->numfrags < MINFRAGS) {
+			woinst->numfrags = MINFRAGS;
+			woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;
+		}
+
+	} else if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE)
+		woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size;
+
+	DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size);
+	DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags);
+}
+
+static void calculate_ifrag(struct wiinst *wiinst)
+{
+	u32 fragsize, bytespersec;
+
+	if (wiinst->fragment_size)
+		return;
+
+	bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitsperchannel >> 3) * wiinst->wave_fmt.samplingrate;
+
+	if (!wiinst->ossfragshift) {
+		fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1;
+
+		while (fragsize) {
+			fragsize >>= 1;
+			wiinst->ossfragshift++;
+		}
+	}
+
+	if (wiinst->ossfragshift < WAVEIN_MINFRAGSHIFT)
+		wiinst->ossfragshift = WAVEIN_MINFRAGSHIFT;
+
+	wiinst->fragment_size = 1 << wiinst->ossfragshift;
+
+	if (!wiinst->numfrags)
+		wiinst->numfrags = (bytespersec * WAVEIN_DEFAULTBUFLEN) / (wiinst->fragment_size * 1000) - 1;
+
+	if (wiinst->numfrags < MINFRAGS)
+		wiinst->numfrags = MINFRAGS;
+
+	if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) {
+		wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size;
+
+		if (wiinst->numfrags < MINFRAGS) {
+			wiinst->numfrags = MINFRAGS;
+			wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;
+		}
+	} else if (wiinst->numfrags * wiinst->fragment_size < WAVEIN_MINBUFSIZE)
+		wiinst->numfrags = WAVEIN_MINBUFSIZE / wiinst->fragment_size;
+
+	DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size);
+	DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags);
+}
+
+void emu10k1_wavein_bh(unsigned long refdata)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in = wiinst->wave_in;
+	u32 bytestocopy, curpos;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wiinst->lock, flags);
+
+	if (wave_in->state == CARDWAVE_STATE_STOPPED) {
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		return;
+	}
+
+	emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &curpos);
+
+	wiinst->total_recorded += curpos - wiinst->curpos;
+
+	if (curpos < wiinst->curpos)
+		wiinst->total_recorded += wiinst->fragment_size * wiinst->numfrags;
+
+	wiinst->curpos = curpos;
+
+	if (wiinst->mapped) {
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		return;
+	}
+
+	spin_unlock_irqrestore(&wiinst->lock, flags);
+
+	if (bytestocopy >= wiinst->fragment_size)
+		wake_up_interruptible(&wiinst->wait_queue);
+	else
+		DPD(4, "Not enough transfer size, %d\n", bytestocopy);
+
+	return;
+}
+
+void emu10k1_waveout_bh(unsigned long refdata)
+{
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out = woinst->wave_out;
+	u32 bytestocopy, pending, curpos;
+	unsigned long flags;
+
+	spin_lock_irqsave(&woinst->lock, flags);
+
+	if (wave_out->state == CARDWAVE_STATE_STOPPED) {
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		return;
+	}
+
+	emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &curpos);
+
+	woinst->total_played += curpos - woinst->curpos;
+
+	if (curpos < woinst->curpos)
+		woinst->total_played += woinst->fragment_size * woinst->numfrags;
+
+	woinst->curpos = curpos;
+
+	if (woinst->mapped) {
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		return;
+	}
+
+	if (wave_out->fill_silence) {
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		emu10k1_waveout_fillsilence(woinst);
+	} else
+		spin_unlock_irqrestore(&woinst->lock, flags);
+
+	if (bytestocopy >= woinst->fragment_size)
+		wake_up_interruptible(&woinst->wait_queue);
+	else
+		DPD(4, "Not enough transfer size -> %x\n", bytestocopy);
+
+	return;
+}
+
+struct file_operations emu10k1_audio_fops = {
+	llseek:emu10k1_audio_llseek,
+	read:emu10k1_audio_read,
+	write:emu10k1_audio_write,
+	poll:emu10k1_audio_poll,
+	ioctl:emu10k1_audio_ioctl,
+	mmap:emu10k1_audio_mmap,
+	open:emu10k1_audio_open,
+	release:emu10k1_audio_release,
+};
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.h linux/drivers/sound/emu10k1/audio.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/audio.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,46 @@
+/*
+ **********************************************************************
+ *     audio.c -- /dev/dsp interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999	    Alan Cox        cleaned up types/leaks
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _AUDIO_H
+#define _AUDIO_H
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+
+#define MINFRAGS	2	/* _don't_ got bellow 2 */
+
+void emu10k1_waveout_bh(unsigned long);
+void emu10k1_wavein_bh(unsigned long);
+
+#endif /* _AUDIO_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.c linux/drivers/sound/emu10k1/cardmi.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardmi.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,813 @@
+
+/*
+ **********************************************************************
+ *     sblive_mi.c - MIDI UART input HAL for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        clean up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "cardmi.h"
+
+static struct {
+	int (*Fn) (struct emu10k1_mpuin *, u8);
+} midistatefn[] = {
+
+	{
+	sblive_miStateParse}, {
+	sblive_miState3Byte},	/* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */
+	{
+	sblive_miState3ByteKey},	/* Byte 1                       */
+	{
+	sblive_miState3ByteVel},	/* Byte 2                       */
+	{
+	sblive_miState2Byte},	/* 0xCn, 0xDn                   */
+	{
+	sblive_miState2ByteKey},	/* Byte 1                       */
+	{
+	sblive_miStateSysCommon2},	/* 0xF1 , 0xF3                  */
+	{
+	sblive_miStateSysCommon2Key},	/* 0xF1 , 0xF3, Byte 1          */
+	{
+	sblive_miStateSysCommon3},	/* 0xF2                         */
+	{
+	sblive_miStateSysCommon3Key},	/* 0xF2 , Byte 1                */
+	{
+	sblive_miStateSysCommon3Vel},	/* 0xF2 , Byte 2                */
+	{
+	sblive_miStateSysExNorm},	/* 0xF0, 0xF7, Normal mode      */
+	{
+	sblive_miStateSysReal}	/* 0xF4 - 0xF6 ,0xF8 - 0xFF     */
+};
+
+/* Installs the IRQ handler for the MPU in port                 */
+
+/* and initialize parameters                                    */
+
+int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
+{
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
+
+	DPF(2, "emu10k1_mpuin_open\n");
+
+	if (!(card_mpuin->status & FLAGS_AVAILABLE))
+		return CTSTATUS_INUSE;
+
+	/* Copy open info and mark channel as in use */
+	card_mpuin->openinfo = *openinfo;
+	card_mpuin->status &= ~FLAGS_AVAILABLE;	/* clear */
+	card_mpuin->status |= FLAGS_READY;	/* set */
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;	/* clear */
+	card_mpuin->firstmidiq = NULL;
+	card_mpuin->lastmidiq = NULL;
+	card_mpuin->qhead = 0;
+	card_mpuin->qtail = 0;
+
+	sblive_miStateInit(card_mpuin);
+
+	emu10k1_mpu_reset(card);
+	emu10k1_mpu_acquire(card);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int emu10k1_mpuin_close(struct emu10k1_card *card)
+{
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
+
+	DPF(2, "emu10k1_mpuin_close()\n");
+
+	/* Check if there are pending input SysEx buffers */
+	if (card_mpuin->firstmidiq != NULL) {
+		ERROR();
+		return CTSTATUS_ERROR;
+	}
+
+	/* Disable RX interrupt */
+	emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
+
+	emu10k1_mpu_release(card);
+
+	card_mpuin->status |= FLAGS_AVAILABLE;	/* set */
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;	/* clear */
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* Adds MIDI buffer to local queue list                         */
+
+int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr *midihdr)
+{
+	struct midi_queue *midiq;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_mpuin_add_buffer()\n");
+
+	/* Update MIDI buffer flags */
+	midihdr->flags |= MIDIBUF_INQUEUE;	/* set */
+	midihdr->flags &= ~MIDIBUF_DONE;	/* clear */
+
+	if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
+		/* Message lost */
+		return CTSTATUS_ERROR;
+	}
+
+	midiq->next = NULL;
+	midiq->qtype = 1;
+	midiq->length = midihdr->bufferlength;
+	midiq->sizeLeft = midihdr->bufferlength;
+	midiq->midibyte = midihdr->data;
+	midiq->refdata = (unsigned long) midihdr;
+
+	spin_lock_irqsave(&card_mpuin->lock, flags);
+
+	if (card_mpuin->firstmidiq == NULL) {
+		card_mpuin->firstmidiq = midiq;
+		card_mpuin->lastmidiq = midiq;
+	} else {
+		(card_mpuin->lastmidiq)->next = midiq;
+		card_mpuin->lastmidiq = midiq;
+	}
+
+	spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* First set the Time Stamp if MIDI IN has not started.         */
+
+/* Then enable RX Irq.                                          */
+
+int emu10k1_mpuin_start(struct emu10k1_card *card)
+{
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
+	u8 dummy;
+
+	DPF(2, "emu10k1_mpuin_start()\n");
+
+	/* Set timestamp if not set */
+	if (card_mpuin->status & FLAGS_MIDM_STARTED) {
+		DPF(2, "Time Stamp not changed\n");
+	} else {
+		while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS);
+
+		card_mpuin->status |= FLAGS_MIDM_STARTED;	/* set */
+
+		/* Set new time stamp */
+		card_mpuin->timestart = (jiffies * 1000) / HZ;
+		DPD(2, "New Time Stamp = %d\n", card_mpuin->timestart);
+
+		card_mpuin->qhead = 0;
+		card_mpuin->qtail = 0;
+
+		emu10k1_irq_enable(card, INTE_MIDIRXENABLE);
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* Disable the RX Irq.  If a partial recorded buffer            */
+
+/* exist, send it up to IMIDI level.                            */
+
+int emu10k1_mpuin_stop(struct emu10k1_card *card)
+{
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
+	struct midi_queue *midiq;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_mpuin_stop()\n");
+
+	emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
+
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;	/* clear */
+
+	if (card_mpuin->firstmidiq) {
+		spin_lock_irqsave(&card_mpuin->lock, flags);
+
+		midiq = card_mpuin->firstmidiq;
+		if (midiq != NULL) {
+			if (midiq->sizeLeft == midiq->length)
+				midiq = NULL;
+			else {
+				card_mpuin->firstmidiq = midiq->next;
+				if (card_mpuin->firstmidiq == NULL)
+					card_mpuin->lastmidiq = NULL;
+			}
+		}
+
+		spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+		if (midiq) {
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
+			kfree(midiq);
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* Disable the RX Irq.  If any buffer                           */
+
+/* exist, send it up to IMIDI level.                            */
+int emu10k1_mpuin_reset(struct emu10k1_card *card)
+{
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
+	struct midi_queue *midiq;
+
+	DPF(2, "emu10k1_mpuin_reset()\n");
+
+	emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
+
+	while (card_mpuin->firstmidiq) {
+		midiq = card_mpuin->firstmidiq;
+		card_mpuin->firstmidiq = midiq->next;
+
+		if (midiq->sizeLeft == midiq->length)
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
+		else
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
+
+		kfree(midiq);
+	}
+
+	card_mpuin->lastmidiq = NULL;
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* Passes the message with the data back to the client          */
+
+/* via IRQ & DPC callbacks to Ring 3                            */
+int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid)
+{
+	unsigned long timein;
+	struct midi_queue *midiq;
+	unsigned long callback_msg[3];
+	struct midi_hdr *midihdr;
+
+	/* Called during ISR. The data & code touched are:
+	 * 1. card_mpuin
+	 * 2. The function to be called
+	 */
+
+	timein = card_mpuin->timein;
+	if (card_mpuin->timestart <= timein)
+		callback_msg[0] = timein - card_mpuin->timestart;
+	else
+		callback_msg[0] = (~0x0L - card_mpuin->timestart) + timein;
+
+	if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR) {
+		callback_msg[1] = data;
+		callback_msg[2] = bytesvalid;
+		DPD(2, "emu10k1_mpuin_callback: midimsg = %lx\n", data);
+	} else {
+		midiq = (struct midi_queue *) data;
+		midihdr = (struct midi_hdr *) midiq->refdata;
+
+		callback_msg[1] = midiq->length - midiq->sizeLeft;
+		callback_msg[2] = midiq->refdata;
+		midihdr->flags &= ~MIDIBUF_INQUEUE;
+		midihdr->flags |= MIDIBUF_DONE;
+
+		midihdr->bytesrecorded = midiq->length - midiq->sizeLeft;
+	}
+
+	/* Notify client that Sysex buffer has been sent */
+	emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg);
+
+	return CTSTATUS_SUCCESS;
+}
+
+void emu10k1_mpuin_bh(unsigned long refdata)
+{
+	u8 data;
+	unsigned idx;
+	struct emu10k1_mpuin *card_mpuin = (struct emu10k1_mpuin *) refdata;
+	unsigned long flags;
+
+	while (card_mpuin->qhead != card_mpuin->qtail) {
+		spin_lock_irqsave(&card_mpuin->lock, flags);
+		idx = card_mpuin->qhead;
+		data = card_mpuin->midiq[idx].data;
+		card_mpuin->timein = card_mpuin->midiq[idx].timein;
+		idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
+		card_mpuin->qhead = idx;
+		spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+		sblive_miStateEntry(card_mpuin, data);
+	}
+
+	return;
+}
+
+/* IRQ callback handler routine for the MPU in port */
+
+int emu10k1_mpuin_irqhandler(struct emu10k1_card *card)
+{
+	unsigned idx;
+	unsigned count;
+	u8 MPUIvalue;
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
+
+	/* IRQ service routine. The data and code touched are:
+	 * 1. card_mpuin
+	 */
+
+	count = 0;
+	idx = card_mpuin->qtail;
+
+	while (1) {
+		if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) {
+			++count;
+			card_mpuin->midiq[idx].data = MPUIvalue;
+			card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ;
+			idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
+		} else {
+			break;
+		}
+	}
+
+	if (count) {
+		card_mpuin->qtail = idx;
+
+		tasklet_hi_schedule(&card_mpuin->tasklet);
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+/*****************************************************************************/
+
+/*   Supporting functions for Midi-In Interpretation State Machine           */
+
+/*****************************************************************************/
+
+/* FIXME: This should be a macro */
+int sblive_miStateInit(struct emu10k1_mpuin *card_mpuin)
+{
+	card_mpuin->status = 0;	/* For MIDI running status */
+	card_mpuin->fstatus = 0;	/* For 0xFn status only */
+	card_mpuin->curstate = STIN_PARSE;
+	card_mpuin->laststate = STIN_PARSE;
+	card_mpuin->data = 0;
+	card_mpuin->timestart = 0;
+	card_mpuin->timein = 0;
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* FIXME: This should be a macro */
+int sblive_miStateEntry(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
+}
+
+int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	switch (data & 0xf0) {
+	case 0x80:
+	case 0x90:
+	case 0xA0:
+	case 0xB0:
+	case 0xE0:
+		card_mpuin->curstate = STIN_3BYTE;
+		break;
+
+	case 0xC0:
+	case 0xD0:
+		card_mpuin->curstate = STIN_2BYTE;
+		break;
+
+	case 0xF0:
+		/* System messages do not affect the previous running status! */
+		switch (data & 0x0f) {
+		case 0x0:
+			card_mpuin->laststate = card_mpuin->curstate;
+			card_mpuin->curstate = STIN_SYS_EX_NORM;
+
+			if (card_mpuin->firstmidiq) {
+				struct midi_queue *midiq;
+
+				midiq = card_mpuin->firstmidiq;
+				*midiq->midibyte = data;
+				--midiq->sizeLeft;
+				++midiq->midibyte;
+			}
+
+			return CTSTATUS_NEXT_BYTE;
+
+		case 0x7:
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0);
+			return CTSTATUS_ERROR;
+
+		case 0x2:
+			card_mpuin->laststate = card_mpuin->curstate;
+			card_mpuin->curstate = STIN_SYS_COMMON_3;
+			break;
+
+		case 0x1:
+		case 0x3:
+			card_mpuin->laststate = card_mpuin->curstate;
+			card_mpuin->curstate = STIN_SYS_COMMON_2;
+			break;
+
+		default:
+			/* includes 0xF4 - 0xF6, 0xF8 - 0xFF */
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+		}
+
+		break;
+
+	default:
+		DPF(2, "BUG: default case hit\n");
+		return CTSTATUS_ERROR;
+	}
+
+	return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
+}
+
+int sblive_miState3Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	u8 temp = data & 0xf0;
+
+	if (temp < 0x80) {
+		return midistatefn[STIN_3BYTE_KEY].Fn(card_mpuin, data);
+	} else if (temp <= 0xe0 && temp != 0xc0 && temp != 0xd0) {
+		card_mpuin->status = data;
+		card_mpuin->curstate = STIN_3BYTE_KEY;
+
+		return CTSTATUS_NEXT_BYTE;
+	}
+
+	return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
+}
+
+int sblive_miState3ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
+
+/* byte 1 */
+{
+	unsigned long tmp;
+
+	if (data > 0x7f) {
+		/* Real-time messages check */
+		if (data > 0xf7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = STIN_PARSE;
+		tmp = ((unsigned long) data) << 8;
+		tmp |= (unsigned long) card_mpuin->status;
+
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->data = data;
+	card_mpuin->curstate = STIN_3BYTE_VEL;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data)
+
+/* byte 2 */
+{
+	unsigned long tmp;
+
+	if (data > 0x7f) {
+		/* Real-time messages check */
+		if (data > 0xf7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = STIN_PARSE;
+		tmp = ((unsigned long) data) << 8;
+		tmp |= card_mpuin->data;
+		tmp = tmp << 8;
+		tmp |= (unsigned long) card_mpuin->status;
+
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = STIN_3BYTE;
+	tmp = (unsigned long) data;
+	tmp = tmp << 8;
+	tmp |= (unsigned long) card_mpuin->data;
+	tmp = tmp << 8;
+	tmp |= (unsigned long) card_mpuin->status;
+
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	u8 temp = data & 0xf0;
+
+	if ((temp == 0xc0) || (temp == 0xd0)) {
+		card_mpuin->status = data;
+		card_mpuin->curstate = STIN_2BYTE_KEY;
+
+		return CTSTATUS_NEXT_BYTE;
+	}
+
+	if (temp < 0x80)
+		return midistatefn[STIN_2BYTE_KEY].Fn(card_mpuin, data);
+
+	return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
+}
+
+int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
+
+/* byte 1 */
+{
+	unsigned long tmp;
+
+	if (data > 0x7f) {
+		/* Real-time messages check */
+		if (data > 0xf7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = STIN_PARSE;
+		tmp = (unsigned long) data;
+		tmp = tmp << 8;
+		tmp |= (unsigned long) card_mpuin->status;
+
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = STIN_2BYTE;
+	tmp = (unsigned long) data;
+	tmp = tmp << 8;
+	tmp |= (unsigned long) card_mpuin->status;
+
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	card_mpuin->fstatus = data;
+	card_mpuin->curstate = STIN_SYS_COMMON_2_KEY;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data)
+
+/* byte 1 */
+{
+	unsigned long tmp;
+
+	if (data > 0x7f) {
+		/* Real-time messages check */
+		if (data > 0xf7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+		tmp = (unsigned long) data;
+		tmp = tmp << 8;
+		tmp |= (unsigned long) card_mpuin->fstatus;
+
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = card_mpuin->laststate;
+	tmp = (unsigned long) data;
+	tmp = tmp << 8;
+	tmp |= (unsigned long) card_mpuin->fstatus;
+
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	card_mpuin->fstatus = data;
+	card_mpuin->curstate = STIN_SYS_COMMON_3_KEY;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *card_mpuin, u8 data)
+
+/* byte 1 */
+{
+	unsigned long tmp;
+
+	if (data > 0x7f) {
+		/* Real-time messages check */
+		if (data > 0xf7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+		tmp = (unsigned long) data;
+		tmp = tmp << 8;
+		tmp |= (unsigned long) card_mpuin->fstatus;
+
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->data = data;
+	card_mpuin->curstate = STIN_SYS_COMMON_3_VEL;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data)
+
+/* byte 2 */
+{
+	unsigned long tmp;
+
+	if (data > 0x7f) {
+		/* Real-time messages check */
+		if (data > 0xf7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+		tmp = (unsigned long) data;
+		tmp = tmp << 8;
+		tmp |= (unsigned long) card_mpuin->data;
+		tmp = tmp << 8;
+		tmp |= (unsigned long) card_mpuin->fstatus;
+
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = card_mpuin->laststate;
+	tmp = (unsigned long) data;
+	tmp = tmp << 8;
+	tmp |= (unsigned long) card_mpuin->data;
+	tmp = tmp << 8;
+	tmp |= (unsigned long) card_mpuin->fstatus;
+
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	unsigned long flags;
+
+	if ((data > 0x7f) && (data != 0xf7)) {
+		/* Real-time messages check */
+		if (data > 0xf7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid Data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+
+		if (card_mpuin->firstmidiq) {
+			struct midi_queue *midiq;
+
+			midiq = card_mpuin->firstmidiq;
+			*midiq->midibyte = data;
+			--midiq->sizeLeft;
+			++midiq->midibyte;
+
+			spin_lock_irqsave(&card_mpuin->lock, flags);
+
+			card_mpuin->firstmidiq = midiq->next;
+			if (card_mpuin->firstmidiq == NULL)
+				card_mpuin->lastmidiq = NULL;
+
+			spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
+
+			kfree(midiq);
+		}
+
+		return CTSTATUS_ERROR;
+	}
+
+	if (card_mpuin->firstmidiq) {
+		struct midi_queue *midiq;
+
+		midiq = card_mpuin->firstmidiq;
+		*midiq->midibyte = data;
+		--midiq->sizeLeft;
+		++midiq->midibyte;
+	}
+
+	if (data == 0xf7) {
+		/* End of Sysex buffer */
+		/* Send down the buffer */
+
+		card_mpuin->curstate = card_mpuin->laststate;
+
+		if (card_mpuin->firstmidiq) {
+			struct midi_queue *midiq;
+
+			midiq = card_mpuin->firstmidiq;
+
+			spin_lock_irqsave(&card_mpuin->lock, flags);
+
+			card_mpuin->firstmidiq = midiq->next;
+			if (card_mpuin->firstmidiq == NULL)
+				card_mpuin->lastmidiq = NULL;
+
+			spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
+
+			kfree(midiq);
+		}
+
+		return CTSTATUS_SUCCESS;
+	}
+
+	if (card_mpuin->firstmidiq) {
+		struct midi_queue *midiq;
+
+		midiq = card_mpuin->firstmidiq;
+
+		if (midiq->sizeLeft == 0) {
+			/* Special case */
+
+			spin_lock_irqsave(&card_mpuin->lock, flags);
+
+			card_mpuin->firstmidiq = midiq->next;
+			if (card_mpuin->firstmidiq == NULL)
+				card_mpuin->lastmidiq = NULL;
+
+			spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
+
+			kfree(midiq);
+
+			return CTSTATUS_NEXT_BYTE;
+		}
+	}
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+int sblive_miStateSysReal(struct emu10k1_mpuin *card_mpuin, u8 data)
+{
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, data, 1);
+
+	return CTSTATUS_NEXT_BYTE;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.h linux/drivers/sound/emu10k1/cardmi.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardmi.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,113 @@
+/*
+ **********************************************************************
+ *     sblive_mi.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _CARDMI_H
+#define _CARDMI_H
+
+#include "icardmid.h"
+
+typedef enum
+{
+	STIN_PARSE = 0,
+	STIN_3BYTE,                     /* 0x80, 0x90, 0xA0, 0xB0, 0xE0 */
+	STIN_3BYTE_KEY,                 /* Byte 1 */
+	STIN_3BYTE_VEL,                 /* Byte 1 */
+	STIN_2BYTE,                     /* 0xC0, 0xD0 */
+	STIN_2BYTE_KEY,                 /* Byte 1 */
+	STIN_SYS_COMMON_2,              /* 0xF1, 0xF3  */
+	STIN_SYS_COMMON_2_KEY,
+	STIN_SYS_COMMON_3,              /* 0xF2 */
+	STIN_SYS_COMMON_3_KEY,
+	STIN_SYS_COMMON_3_VEL,
+	STIN_SYS_EX_NORM,               /* 0xF0, Normal mode */
+	STIN_SYS_REAL
+} midi_in_state;
+
+
+/* flags for card MIDI in object */
+#define FLAGS_MIDM_STARTED          0x00001000      // Data has started to come in after Midm Start
+#define MIDIIN_MAX_BUFFER_SIZE      200             // Definition for struct emu10k1_mpuin
+
+struct midi_data
+{
+	u8 data;
+	u32 timein;
+};
+
+struct emu10k1_mpuin
+{
+	spinlock_t        lock;
+	struct midi_queue *firstmidiq;
+	struct midi_queue *lastmidiq;
+	unsigned          qhead, qtail;
+	struct midi_data  midiq[MIDIIN_MAX_BUFFER_SIZE];
+	struct tasklet_struct tasklet;
+	struct midi_openinfo    openinfo;
+
+	/* For MIDI state machine */
+	u8              status;        /* For MIDI running status */
+	u8              fstatus;       /* For 0xFn status only */
+	midi_in_state   curstate;
+	midi_in_state   laststate;
+	u32             timestart;
+	u32             timein;
+	u8              data;
+};
+
+int emu10k1_mpuin_open(struct emu10k1_card *, struct midi_openinfo *);
+int emu10k1_mpuin_close(struct emu10k1_card *);
+int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *, struct midi_hdr *);
+int emu10k1_mpuin_start(struct emu10k1_card *);
+int emu10k1_mpuin_stop(struct emu10k1_card *);
+int emu10k1_mpuin_reset(struct emu10k1_card *);
+
+int sblive_miStateInit(struct emu10k1_mpuin *);
+int sblive_miStateEntry(struct emu10k1_mpuin *, u8);
+int sblive_miStateParse(struct emu10k1_mpuin *, u8);
+int sblive_miState3Byte(struct emu10k1_mpuin *, u8);
+int sblive_miState3ByteKey(struct emu10k1_mpuin *, u8);
+int sblive_miState3ByteVel(struct emu10k1_mpuin *, u8);
+int sblive_miState2Byte(struct emu10k1_mpuin *, u8);
+int sblive_miState2ByteKey(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon2(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon3(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysExNorm(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysReal(struct emu10k1_mpuin *, u8);
+
+int emu10k1_mpuin_irqhandler(struct emu10k1_card *);
+void emu10k1_mpuin_bh(unsigned long);
+int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid);
+
+#endif  /* _CARDMI_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.c linux/drivers/sound/emu10k1/cardmo.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardmo.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,229 @@
+
+/*     
+ **********************************************************************
+ *     cardmo.c - MIDI UART output HAL for emu10k1 driver 
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ *     November 2, 1999     Alan Cox        cleaned up
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#include "hwaccess.h"
+#include "cardmo.h"
+
+/* Installs the IRQ handler for the MPU out port               *
+ * and initialize parameters                                    */
+
+int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
+{
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
+
+	DPF(2, "emu10k1_mpuout_open()\n");
+
+	if (!(card_mpuout->status & FLAGS_AVAILABLE))
+		return CTSTATUS_INUSE;
+
+	/* Copy open info and mark channel as in use */
+	card_mpuout->intr = 0;
+	card_mpuout->openinfo = *openinfo;
+	card_mpuout->status &= ~FLAGS_AVAILABLE;
+	card_mpuout->laststatus = 0x80;
+	card_mpuout->firstmidiq = NULL;
+	card_mpuout->lastmidiq = NULL;
+
+	emu10k1_mpu_reset(card);
+	emu10k1_mpu_acquire(card);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int emu10k1_mpuout_close(struct emu10k1_card *card)
+{
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
+	struct midi_queue *midiq;
+	struct midi_hdr *midihdr;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_mpuout_close()\n");
+
+	emu10k1_irq_disable(card, INTE_MIDITXENABLE);
+
+	spin_lock_irqsave(&card_mpuout->lock, flags);
+
+	while (card_mpuout->firstmidiq != NULL) {
+		midiq = card_mpuout->firstmidiq;
+		midihdr = (struct midi_hdr *) midiq->refdata;
+
+		card_mpuout->firstmidiq = midiq->next;
+
+		kfree(midihdr->data);
+		kfree(midihdr);
+		kfree(midiq);
+	}
+
+	card_mpuout->lastmidiq = NULL;
+
+	emu10k1_mpu_release(card);
+
+	card_mpuout->status |= FLAGS_AVAILABLE;
+
+	spin_unlock_irqrestore(&card_mpuout->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* If there isn't enough buffer space, reject Midi Buffer.     *
+* Otherwise, disable TX, create object to hold Midi            *
+*  uffer, update buffer flags and other parameters             *
+* before enabling TX again.                                    */
+
+int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr)
+{
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
+	struct midi_queue *midiq;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_mpuout_add_buffer()\n");
+
+	if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
+		return CTSTATUS_SUCCESS;
+
+	midihdr->flags |= MIDIBUF_INQUEUE;
+	midihdr->flags &= ~MIDIBUF_DONE;
+
+	if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
+		/* Message lost */
+		return CTSTATUS_NOMEMORY;
+	}
+
+	midiq->next = NULL;
+	midiq->qtype = 1;
+	midiq->length = midihdr->bufferlength;
+	midiq->sizeLeft = midihdr->bufferlength;
+	midiq->midibyte = midihdr->data;
+
+	midiq->refdata = (unsigned long) midihdr;
+
+	spin_lock_irqsave(&card_mpuout->lock, flags);
+
+	if (card_mpuout->firstmidiq == NULL) {
+		card_mpuout->firstmidiq = midiq;
+		card_mpuout->lastmidiq = midiq;
+	} else {
+		(card_mpuout->lastmidiq)->next = midiq;
+		card_mpuout->lastmidiq = midiq;
+	}
+
+	card_mpuout->intr = 0;
+
+	emu10k1_irq_enable(card, INTE_MIDITXENABLE);
+
+	spin_unlock_irqrestore(&card_mpuout->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+void emu10k1_mpuout_bh(unsigned long refdata)
+{
+	struct emu10k1_card *card = (struct emu10k1_card *) refdata;
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
+	int cByteSent = 0;
+	int status;
+	struct midi_queue *midiq;
+	struct midi_queue *doneq = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card_mpuout->lock, flags);
+
+	while (card_mpuout->firstmidiq != NULL) {
+		midiq = card_mpuout->firstmidiq;
+
+		while (cByteSent < 4 && midiq->sizeLeft) {
+			status = emu10k1_mpu_write_data(card, *midiq->midibyte);
+
+			if (status == CTSTATUS_SUCCESS) {
+				++cByteSent;
+				--midiq->sizeLeft;
+				++midiq->midibyte;
+			} else {
+				DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
+			}
+		}
+
+		if (midiq->sizeLeft == 0) {
+			if (doneq == NULL)
+				doneq = midiq;
+			card_mpuout->firstmidiq = midiq->next;
+		} else
+			break;
+	}
+
+	if (card_mpuout->firstmidiq == NULL)
+		card_mpuout->lastmidiq = NULL;
+
+	if (doneq != NULL) {
+		while (doneq != card_mpuout->firstmidiq) {
+			unsigned long callback_msg[3];
+
+			midiq = doneq;
+			doneq = midiq->next;
+
+			if (midiq->qtype) {
+				callback_msg[0] = 0;
+				callback_msg[1] = midiq->length;
+				callback_msg[2] = midiq->refdata;
+
+				emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg);
+			} else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F)
+				card_mpuout->laststatus = (u8) midiq->refdata;
+
+			kfree(midiq);
+		}
+	}
+
+	if ((card_mpuout->firstmidiq != NULL) || cByteSent) {
+		card_mpuout->intr = 0;
+		emu10k1_irq_enable(card, INTE_MIDITXENABLE);
+	}
+
+	spin_unlock_irqrestore(&card_mpuout->lock, flags);
+
+	return;
+}
+
+int emu10k1_mpuout_irqhandler(struct emu10k1_card *card)
+{
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
+
+	DPF(4, "emu10k1_mpuout_irqhandler\n");
+
+	card_mpuout->intr = 1;
+	emu10k1_irq_disable(card, INTE_MIDITXENABLE);
+
+	tasklet_hi_schedule(&card_mpuout->tasklet);
+
+	return CTSTATUS_SUCCESS;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.h linux/drivers/sound/emu10k1/cardmo.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardmo.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,61 @@
+/*
+ **********************************************************************
+ *     cardmo.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox	    cleaned up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _CARDMO_H
+#define _CARDMO_H
+
+#include "icardmid.h"
+
+#define CARDMIDIOUT_STATE_DEFAULT    0x00000000
+#define CARDMIDIOUT_STATE_SUSPEND    0x00000001
+
+struct emu10k1_mpuout
+{
+	u32			status;
+	u32			state;
+	volatile int		intr;
+	struct midi_queue	*firstmidiq;
+	struct midi_queue	*lastmidiq;
+	u8			laststatus;
+	struct tasklet_struct 	tasklet;
+	spinlock_t		lock;
+	struct midi_openinfo	openinfo;
+};
+
+int emu10k1_mpuout_open(struct emu10k1_card *, struct midi_openinfo *);
+int emu10k1_mpuout_close(struct emu10k1_card *);
+int emu10k1_mpuout_add_buffer(struct emu10k1_card *, struct midi_hdr *);
+
+int emu10k1_mpuout_irqhandler(struct emu10k1_card *);
+void emu10k1_mpuout_bh(unsigned long);
+
+#endif  /* _CARDMO_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.c linux/drivers/sound/emu10k1/cardwi.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardwi.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,472 @@
+
+/*
+ **********************************************************************
+ *     cardwi.c - PCM input HAL for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "recmgr.h"
+#include "audio.h"
+#include "cardwi.h"
+
+void query_format(int recsrc, struct wave_format *wave_fmt)
+{
+
+	switch (recsrc) {
+	case WAVERECORD_AC97:
+
+		if ((wave_fmt->channels != 2) && (wave_fmt->channels != 1))
+			wave_fmt->channels = 2;
+
+		if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2)
+			wave_fmt->samplingrate = 0xBB80;
+		else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2)
+			wave_fmt->samplingrate = 0xAC44;
+		else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2)
+			wave_fmt->samplingrate = 0x7D00;
+		else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2)
+			wave_fmt->samplingrate = 0x5DC0;
+		else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2)
+			wave_fmt->samplingrate = 0x5622;
+		else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2)
+			wave_fmt->samplingrate = 0x3E80;
+		else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2)
+			wave_fmt->samplingrate = 0x2B11;
+		else
+			wave_fmt->samplingrate = 0x1F40;
+
+		if ((wave_fmt->bitsperchannel != 16) && (wave_fmt->bitsperchannel != 8))
+			wave_fmt->bitsperchannel = 16;
+
+		break;
+
+	case WAVERECORD_MIC:
+		wave_fmt->channels = 1;
+		wave_fmt->samplingrate = 0x1F40;
+		wave_fmt->bitsperchannel = 8;
+		break;
+
+	case WAVERECORD_FX:
+		wave_fmt->channels = 2;
+		wave_fmt->samplingrate = 0xBB80;
+		wave_fmt->bitsperchannel = 16;
+		break;
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+static int alloc_recbuffer(struct wave_in *wave_in, u32 * bufsize, u8 ** buffer)
+{
+	u32 reqsize;
+	int i, j;
+	u32 size[4];
+
+	/* NOTE: record buffer size only can be certain sizes.  If the requested
+	 * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */
+	if (!wave_in->rec_ptr->is_16bit)
+		*bufsize <<= 1;
+
+	if (*bufsize >= 0x10000) {
+		*bufsize = reqsize = 0x10000;
+		wave_in->rec_ptr->bufsize = 31;
+	} else {
+		reqsize = 0;
+		size[0] = 384;
+		size[1] = 448;
+		size[2] = 512;
+		size[3] = 640;
+
+		for (i = 0; i < 8; i++)
+			for (j = 0; j < 4; j++)
+				if (*bufsize >= size[j]) {
+					reqsize = size[j];
+					size[j] = size[j] * 2;
+					wave_in->rec_ptr->bufsize = i * 4 + j + 1;
+				} else
+					goto exitloop;
+	      exitloop:
+		if (reqsize == 0) {
+			reqsize = 384;
+			wave_in->rec_ptr->bufsize = 1;
+		}
+
+		*bufsize = reqsize;
+	}
+
+	DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsize);
+
+	/* Recording buffer must be continuous and page-aligned */
+	if ((wave_in->memhandle = emu10k1_alloc_memphysical(reqsize)) == NULL)
+		return CTSTATUS_ERROR;
+
+	DPD(2, "recbufsize: %x\n", *bufsize);
+
+	*buffer = (u8 *) wave_in->memhandle->virtaddx;
+
+	return CTSTATUS_SUCCESS;
+}
+
+static int get_recbuffer(struct emu10k1_card *card, struct wave_in *wave_in, u32 * size)
+{
+	u8 *buffer;
+
+	wave_in->rec_ptr->card = card;
+	wave_in->rec_ptr->recpos = 0;
+	wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate;
+	wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0;
+	wave_in->rec_ptr->is_16bit = (wave_in->wave_fmt.bitsperchannel == 16) ? 1 : 0;
+
+	/* Allocate buffer here */
+	if (alloc_recbuffer(wave_in, size, &buffer) != CTSTATUS_SUCCESS) {
+		ERROR();
+		return CTSTATUS_ERROR;
+	}
+
+	/* recbufsize contains actual record buffer size          */
+	/* for 8 bit samples the size is twice the requested      */
+	/* value since we only make use of one in every two bytes */
+	wave_in->rec_ptr->recbufsize = *size;
+	wave_in->rec_ptr->recbuffer = buffer;
+	wave_in->rec_ptr->busaddx = wave_in->memhandle->busaddx;
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void dealloc_recbuffer(struct wave_in *wave_in)
+{
+	emu10k1_free_memphysical(wave_in->memhandle);
+	return;
+}
+
+int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in;
+	struct wave_in **wave_in_tmp = NULL;
+	u32 buffsize, bytespersec, delay;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_wavein_open()\n");
+
+	if ((wave_in = (struct wave_in *) kmalloc(sizeof(struct wave_in), GFP_KERNEL)) == NULL) {
+		ERROR();
+		return CTSTATUS_ERROR;
+	}
+
+	wave_in->state = CARDWAVE_STATE_STOPPED;
+	wave_in->wave_fmt = wiinst->wave_fmt;
+	wave_in->memhandle = NULL;
+	wave_in->timer = NULL;
+
+	switch (wiinst->recsrc) {
+	case WAVERECORD_AC97:
+		wave_in_tmp = &card->wavein->ac97;
+		break;
+	case WAVERECORD_MIC:
+		wave_in_tmp = &card->wavein->mic;
+		break;
+	case WAVERECORD_FX:
+		wave_in_tmp = &card->wavein->fx;
+		break;
+	default:
+		break;
+	}
+
+	spin_lock_irqsave(&card->lock, flags);
+	if (*wave_in_tmp != NULL) {
+		spin_unlock_irqrestore(&card->lock, flags);
+		kfree(wave_in);
+		return CTSTATUS_ERROR;
+	}
+
+	*wave_in_tmp = wave_in;
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	wiinst->wave_in = wave_in;
+
+	if ((wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)) == NULL) {
+		ERROR();
+		emu10k1_wavein_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	buffsize = wiinst->fragment_size * wiinst->numfrags;
+
+	if (get_recbuffer(card, wave_in, &buffsize) != CTSTATUS_SUCCESS) {
+		ERROR();
+		emu10k1_wavein_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	wiinst->fragment_size = buffsize / wiinst->numfrags;
+
+	/* This callback size returned is the size in the play buffer.
+	 * For 8-bit samples, callbacksize of user buffer should be
+	 * half of the callbacksize in play buffer. */
+	if (wave_in->wave_fmt.bitsperchannel == 8)
+		wiinst->fragment_size >>= 1;
+
+	wave_in->callbacksize = wiinst->fragment_size;
+
+	emu10k1_set_record_src(wave_in->rec_ptr, wiinst->recsrc);
+
+	bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate);
+	delay = (48000 * wave_in->callbacksize) / bytespersec;
+
+	if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+		ERROR();
+		emu10k1_wavein_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+	unsigned long flags;
+
+	if (wave_in->state != CARDWAVE_STATE_STOPPED)
+		emu10k1_wavein_stop(wave_dev);
+
+	if (wave_in->timer != NULL)
+		emu10k1_timer_uninstall(card, wave_in->timer);
+
+	if (wave_in->memhandle != NULL)
+		dealloc_recbuffer(wave_in);
+
+	if (wave_in->rec_ptr != NULL)
+		kfree(wave_in->rec_ptr);
+
+	spin_lock_irqsave(&card->lock, flags);
+	switch (wave_dev->wiinst->recsrc) {
+	case WAVERECORD_AC97:
+		card->wavein->ac97 = NULL;
+		break;
+	case WAVERECORD_MIC:
+		card->wavein->mic = NULL;
+		break;
+	case WAVERECORD_FX:
+		card->wavein->fx = NULL;
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	kfree(wave_in);
+	wave_dev->wiinst->wave_in = NULL;
+
+	return;
+}
+
+void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev)
+{
+	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+
+	DPF(2, "emu10k1_wavein_start()\n");
+
+	if (wave_in->state == CARDWAVE_STATE_STARTED)
+		return;
+
+	emu10k1_start_record(wave_in->rec_ptr);
+	wave_in->state = CARDWAVE_STATE_STARTED;
+
+	emu10k1_timer_enable(wave_dev->card, wave_in->timer);
+
+	return;
+}
+
+void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev)
+{
+	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+
+	DPF(2, "emu10k1_wavein_stop()\n");
+
+	emu10k1_stop_record(wave_in->rec_ptr);
+	emu10k1_timer_disable(wave_dev->card, wave_in->timer);
+
+	wave_in->rec_ptr->recpos = 0;
+	wave_in->state = CARDWAVE_STATE_STOPPED;
+
+	return;
+}
+
+int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in = wiinst->wave_in;
+	u32 bytespersec, delay;
+
+	DPF(2, "emu10k1_wavein_setformat()\n");
+
+	query_format(wiinst->recsrc, &wiinst->wave_fmt);
+
+	if (!wave_in)
+		return CTSTATUS_SUCCESS;
+
+	if (wave_in->state == CARDWAVE_STATE_STARTED) {
+		wiinst->wave_fmt = wave_in->wave_fmt;
+		return CTSTATUS_SUCCESS;
+	}
+
+	if ((wave_in->wave_fmt.samplingrate != wiinst->wave_fmt.samplingrate)
+	    || (wave_in->wave_fmt.bitsperchannel != wiinst->wave_fmt.bitsperchannel)
+	    || (wave_in->wave_fmt.channels != wiinst->wave_fmt.channels)) {
+
+		emu10k1_timer_uninstall(card, wave_in->timer);
+
+		wave_in->wave_fmt = wiinst->wave_fmt;
+
+		bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate);
+		delay = (48000 * wave_in->callbacksize) / bytespersec;
+
+		if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+			ERROR();
+			emu10k1_wavein_close(wave_dev);
+			return CTSTATUS_ERROR;
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+void emu10k1_wavein_getxfersize(struct wave_in *wave_in, u32 * size, u32 * curpos)
+{
+	struct record *rec_ptr = wave_in->rec_ptr;
+
+	/* Get position of current address, this is in no. of bytes in play buffer */
+	emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, curpos);
+
+	*size = *curpos - rec_ptr->recpos;
+
+	/* Recpos is the actual position in user buffer and play buffer */
+	if (*curpos < rec_ptr->recpos)
+		*size += rec_ptr->recbufsize;
+
+	if (!rec_ptr->is_16bit)
+		*size >>= 1;
+
+	return;
+}
+
+static void copy_s16_to_u8(u8 * dstbuf, s16 * srcbuf, u32 size)
+{
+	u16 sample;
+	u8 byte;
+
+	while (size--) {
+		sample = (*srcbuf) + 32767;
+		byte = (u8) (sample >> 8);
+		copy_to_user(dstbuf, &byte, 1);
+		dstbuf++;
+		srcbuf++;
+	}
+}
+
+/* transfer the data from the wave device.                    */
+void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size)
+{
+	struct wave_in *wave_in = wiinst->wave_in;
+	struct record *rec_ptr = wave_in->rec_ptr;
+	u32 sizetocopy, sizetocopy_now, start;
+	unsigned long flags;
+
+	sizetocopy = min(rec_ptr->recbufsize * (rec_ptr->is_16bit + 1) / 2, *size);
+	*size = sizetocopy;
+
+	if (!sizetocopy)
+		return;
+
+	spin_lock_irqsave(&wiinst->lock, flags);
+
+	sizetocopy_now = (rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is_16bit + 1) / 2;
+
+	start = rec_ptr->recpos;
+
+	if (sizetocopy > sizetocopy_now) {
+		sizetocopy -= sizetocopy_now;
+		rec_ptr->recpos = sizetocopy * 2 / (rec_ptr->is_16bit + 1);
+
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+
+		if (rec_ptr->is_16bit) {
+			copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy_now);
+			copy_to_user(data + sizetocopy_now, rec_ptr->recbuffer, sizetocopy);
+		} else {
+			copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy_now);
+			copy_s16_to_u8(data + sizetocopy_now, (s16 *) rec_ptr->recbuffer, sizetocopy);
+		}
+	} else {
+		if (sizetocopy == sizetocopy_now)
+			rec_ptr->recpos = 0;
+		else
+			rec_ptr->recpos += sizetocopy * 2 / (rec_ptr->is_16bit + 1);
+
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+
+		if (rec_ptr->is_16bit)
+			copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy);
+		else
+			copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy);
+	}
+
+	return;
+}
+
+/* get the specified control value of the wave device. */
+
+int emu10k1_wavein_getcontrol(struct wave_in *wave_in, u32 ctrlid, u32 * value)
+{
+	switch (ctrlid) {
+	case WAVECURPOS:
+		/* There is no actual start yet */
+		if (wave_in->state == CARDWAVE_STATE_STOPPED) {
+			*value = 0;
+		} else {
+			/* value is in byte units */
+			*value = sblive_readptr(wave_in->rec_ptr->card, wave_in->rec_ptr->bufidxreg, 0);
+		}
+
+		break;
+
+	default:
+		return CTSTATUS_ERROR;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.h linux/drivers/sound/emu10k1/cardwi.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardwi.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,92 @@
+/*
+ **********************************************************************
+ *     cardwi.h -- header file for card wave input functions
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+#ifndef _CARDWI_H
+#define _CARDWI_H
+
+#include "icardwav.h"
+
+struct wave_in 
+{
+	struct list_head list;
+
+	u32 state;
+	struct record *rec_ptr;
+	struct memhandle *memhandle;
+	struct emu_timer *timer;
+	u32 callbacksize;
+	struct wave_format wave_fmt;
+};
+
+struct wiinst
+{
+	struct wave_in *wave_in;
+	struct wave_format wave_fmt;
+	u16 ossfragshift;
+	u32 fragment_size;
+	u32 numfrags;
+	wait_queue_head_t wait_queue;
+	int mapped;
+	u32 total_recorded;
+	u32 blocks;
+	u32 curpos;
+	spinlock_t lock;
+	u8 recsrc;
+};
+
+struct emu10k1_wavein 
+{
+	struct wave_in *ac97;
+	struct wave_in *mic;
+	struct wave_in *fx;
+
+	u8 recsrc;
+};
+
+
+#define WAVEIN_MAXBUFSIZE         65536
+#define WAVEIN_MINBUFSIZE	  368
+
+#define WAVEIN_DEFAULTFRAGLEN     100 
+#define WAVEIN_DEFAULTBUFLEN      1000
+
+#define WAVEIN_MINFRAGSHIFT   	  8 
+
+int emu10k1_wavein_open(struct emu10k1_wavedevice *);
+void emu10k1_wavein_close(struct emu10k1_wavedevice *);
+void emu10k1_wavein_start(struct emu10k1_wavedevice *);
+void emu10k1_wavein_stop(struct emu10k1_wavedevice *);
+void emu10k1_wavein_getxfersize(struct wave_in *, u32 *, u32 *);
+void emu10k1_wavein_xferdata(struct wiinst *, u8 *, u32 *);
+int emu10k1_wavein_setformat(struct emu10k1_wavedevice *);
+int emu10k1_wavein_getcontrol(struct wave_in *, u32, u32 *);
+
+
+#endif /* _CARDWI_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.c linux/drivers/sound/emu10k1/cardwo.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardwo.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,755 @@
+
+/*
+ **********************************************************************
+ *     cardwo.c - PCM output HAL for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "cardwo.h"
+#include "audio.h"
+
+/* Volume calcs */
+
+static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left)
+{
+	/* only applicable for playback */
+	u32 volL, volR, vol = 0;
+
+	volL = (wave_out->localvol & 0xffff);
+	volR = ((wave_out->localvol >> 16) & 0xffff);
+
+	if (wave_out->globalvolFactor) {
+		volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff;
+		volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff;
+	}
+
+	/* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */
+	/* New volume and pan */
+
+	if (volL == volR) {
+		vol = volL;
+		left->send_c = 0xff;
+		left->send_b = 0xff;
+	} else {
+		if (volL > volR) {
+			vol = volL;
+			left->send_c = 0xff;
+			left->send_b = (char) ((volR * 255) / vol);
+		} else {
+			vol = volR;
+			left->send_b = 0xff;
+			left->send_c = (char) ((volL * 255) / vol);
+		}
+	}
+
+	left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2);
+
+	return vol;
+}
+
+static void query_format(struct wave_format *wave_fmt)
+{
+	if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
+		wave_fmt->channels = 2;
+
+	if (wave_fmt->samplingrate >= 0x2EE00)
+		wave_fmt->samplingrate = 0x2EE00;
+
+	if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16))
+		wave_fmt->bitsperchannel = 16;
+
+	return;
+}
+
+static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer)
+{
+	u32 numpages, reqsize, pageindex, pagecount;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	unsigned long busaddx;
+	int i;
+
+	reqsize = *size;
+	numpages = reqsize / PAGE_SIZE;
+
+	/* If size is not a multiple of PAGE_SIZE then we need to round up */
+	if (reqsize % PAGE_SIZE)
+		numpages += 1;
+
+	DPD(2, "requested pages is: %d\n", numpages);
+
+	wavexferbuf->numpages = numpages;
+
+	/* Only for playback, request for emu address space */
+	/* Support non page-aligned buffer, don't need interpolation page */
+
+	if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0)
+		return CTSTATUS_ERROR;
+
+	if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL)
+		return CTSTATUS_ERROR;
+
+	/* Fill in virtual memory table */
+	for (pagecount = 0; pagecount < numpages; pagecount++) {
+		if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) {
+			wavexferbuf->numpages = pagecount;
+			return CTSTATUS_ERROR;
+		}
+
+		DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]);
+
+		for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
+			busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE);
+
+			DPD(3, "Bus Addx: %lx\n", busaddx);
+
+			pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
+
+			((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex;
+		}
+	}
+
+	*buffer = wave_out->pagetable;
+
+	return CTSTATUS_SUCCESS;
+}
+
+static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size)
+{
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	void **buffer;
+
+	wavexferbuf->xferpos = 0;
+	wavexferbuf->silence_xferpos = 0;
+	wavexferbuf->stopposition = 0;
+	wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
+	wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
+	wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
+
+	if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	/* xferbufsize contains actual transfer buffer size */
+	wavexferbuf->xferbufsize = *size;
+	wavexferbuf->xferbuffer = buffer;
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out)
+{
+	u32 pagecount, pageindex;
+	int i;
+
+	if (wave_out->pagetable != NULL) {
+		for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) {
+			free_page((unsigned long) wave_out->pagetable[pagecount]);
+
+			for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
+				pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
+				((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex;
+			}
+		}
+		kfree(wave_out->pagetable);
+	}
+
+	emu10k1_addxmgr_free(card, wave_out->emupageindex);
+
+	return;
+}
+
+static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device)
+{
+	struct emu10k1_waveout *card_waveout = card->waveout;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	struct voice_allocdesc voice_allocdesc;
+	struct voice_param *left, *right;
+	u32 size;
+
+	/* Allocate voices here, if no voices available, return error.
+	 * Init voice_allocdesc first.*/
+
+	voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK;
+
+	voice_allocdesc.flags = 0;
+
+	if (device == 1)
+		voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2;
+
+	if (wave_out->wave_fmt.channels == 1)
+		voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO;
+
+	if (wave_out->wave_fmt.bitsperchannel == 16)
+		voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT;
+
+	if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL)
+		return CTSTATUS_ERROR;
+
+	/* voice initialization */
+
+	left = &wave_out->voice->params;
+
+	/* Calculate pitch */
+	left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8);
+
+	DPD(2, "Initial pitch --> %x\n", left->initial_pitch);
+
+	/* Easy way out.. gotta calculate value */
+	left->pitch_target = 0;
+	left->volume_target = 0;
+	left->FC_target = 0;
+
+	left->byampl_env_sustain = 0x7f;
+	left->byampl_env_decay = 0x7f;
+
+	if (wave_out->globalreverbFactor) {
+		u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff);
+
+		left->send_a = (t > 255) ? 255 : t;
+	} else {
+		left->send_a = 0;
+	}
+
+	if (wave_out->globalchorusFactor) {
+		u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff);
+
+		left->send_d = (t > 255) ? 255 : t;
+	} else {
+		left->send_d = 0;
+	}
+
+	set_volume_instance(card_waveout, wave_out, left);
+
+	left->pan_target = left->send_c;
+	left->aux_target = left->send_b;
+
+	size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample;
+	left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample;
+	left->end = left->start + size;
+	left->startloop = left->start;
+	left->endloop = left->end;
+
+	if (wave_out->voice->linked_voice) {
+		DPF(2, "is stereo\n");
+		right = &wave_out->voice->linked_voice->params;
+
+		right->initial_pitch = left->initial_pitch;
+
+		/* Easy way out.. gotta calculate value */
+		right->pitch_target = 0;
+		right->volume_target = 0;
+		right->FC_target = 0;
+
+		right->byampl_env_sustain = 0x7f;
+		right->byampl_env_decay = 0x7f;
+
+		right->send_d = left->send_d;
+		right->send_a = left->send_a;
+
+		/* Left output of right channel is always zero */
+		right->send_c = 0;
+
+		/* Update right channel aux */
+		right->pan_target = 0;
+		right->send_b = left->send_b;
+		right->aux_target = right->send_b;
+
+		/* Zero out right output of left channel */
+		left->send_b = 0;
+		left->aux_target = 0;
+
+		/* Update right channel attenuation */
+		right->initial_attn = left->initial_attn;
+
+		right->start = left->start;
+		right->end = left->end;
+		right->startloop = left->startloop;
+		right->endloop = left->endloop;
+
+	}
+
+	DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out;
+	u32 bytespersec, delay;
+	u32 buffsize;
+
+	DPF(2, "emu10k1_waveout_open()\n");
+
+	if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	woinst->wave_out = wave_out;
+
+	/* Init channel object */
+	wave_out->state = CARDWAVE_STATE_STOPPED;
+	wave_out->wave_fmt = woinst->wave_fmt;
+	wave_out->voice = NULL;
+	wave_out->emupageindex = -1;
+	wave_out->wavexferbuf = NULL;
+	wave_out->pagetable = NULL;
+	wave_out->timer = NULL;
+
+	/* Assign default local volume */
+	/* FIXME: Should we be maxing the initial values like this? */
+	wave_out->localvol = 0xffffffff;
+	wave_out->localreverb = 0xffffffff;
+	wave_out->localchorus = 0xffffffff;
+	wave_out->globalvolFactor = 0xffff;
+	wave_out->globalreverbFactor = 0xffff;
+	wave_out->globalchorusFactor = 0xffff;
+
+	wave_out->setpos = 0;
+	wave_out->position = 0;
+
+	wave_out->fill_silence = 0;
+
+	if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	buffsize = woinst->fragment_size * woinst->numfrags;
+
+	if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	woinst->fragment_size = buffsize / woinst->numfrags;
+	wave_out->callbacksize = woinst->fragment_size;
+
+	if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
+	delay = (48000 * wave_out->callbacksize) / bytespersec;
+
+	if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct wave_out *wave_out = wave_dev->woinst->wave_out;
+
+	DPF(2, "emu10k1_waveout_close()\n");
+
+	if (wave_out->state != CARDWAVE_STATE_STOPPED)
+		emu10k1_waveout_stop(wave_dev);
+
+	if (wave_out->timer != NULL)
+		emu10k1_timer_uninstall(card, wave_out->timer);
+
+	if (wave_out->voice != NULL)
+		emu10k1_voice_free(&card->voicemgr, wave_out->voice);
+
+	if (wave_out->emupageindex >= 0)
+		dealloc_xferbuffer(card, wave_out);
+
+	if (wave_out->wavexferbuf != NULL)
+		kfree(wave_out->wavexferbuf);
+
+	kfree(wave_out);
+	wave_dev->woinst->wave_out = NULL;
+
+	return;
+}
+
+int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct wave_out *wave_out = wave_dev->woinst->wave_out;
+	u32 start, startPosition;
+
+	DPF(2, "emu10k1_waveout_start()\n");
+
+	/* If already started, return success */
+	if (wave_out->state == CARDWAVE_STATE_STARTED)
+		return CTSTATUS_SUCCESS;
+
+	if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos)
+		startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample);
+	else
+		startPosition = wave_out->wavexferbuf->stopposition;
+
+	start = wave_out->voice->params.start;
+	wave_out->voice->params.start += startPosition;
+
+	DPD(2, "CA is %x\n", wave_out->voice->params.start);
+
+	emu10k1_voice_playback_setup(wave_out->voice);
+
+	wave_out->voice->params.start = start;
+
+	/* Actual start */
+	emu10k1_voice_start(wave_out->voice);
+
+	wave_out->state = CARDWAVE_STATE_STARTED;
+	wave_out->setpos = 0;
+
+	emu10k1_timer_enable(card, wave_out->timer);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out = woinst->wave_out;
+	u32 bytespersec, delay;
+
+	DPF(2, "emu10k1_waveout_setformat()\n");
+
+	query_format(&woinst->wave_fmt);
+
+	if (wave_out == NULL)
+		return CTSTATUS_SUCCESS;
+
+	if (wave_out->state == CARDWAVE_STATE_STARTED) {
+		woinst->wave_fmt = wave_out->wave_fmt;
+		return CTSTATUS_SUCCESS;
+	}
+
+	if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate)
+	    || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel)
+	    || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) {
+		struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+
+		emu10k1_timer_uninstall(card, wave_out->timer);
+
+		emu10k1_voice_free(&card->voicemgr, wave_out->voice);
+
+		wave_out->wave_fmt = woinst->wave_fmt;
+		wave_out->timer = NULL;
+
+		wavexferbuf->xferpos = 0;
+		wavexferbuf->silence_xferpos = 0;
+		wavexferbuf->stopposition = 0;
+		wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
+		wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
+		wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
+
+		if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
+			ERROR();
+			emu10k1_waveout_close(wave_dev);
+			return CTSTATUS_ERROR;
+		}
+
+		bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
+		delay = (48000 * wave_out->callbacksize) / bytespersec;
+
+		if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+			ERROR();
+			emu10k1_waveout_close(wave_dev);
+			return CTSTATUS_ERROR;
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct wave_out *wave_out = wave_dev->woinst->wave_out;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	u32 samples = 32;
+	u32 position;
+
+	DPF(2, "emu10k1_waveout_stop()\n");
+
+	if (wave_out->state == CARDWAVE_STATE_STOPPED)
+		return;
+
+	emu10k1_timer_disable(card, wave_out->timer);
+
+	/* Stop actual voice */
+	emu10k1_voice_stop(wave_out->voice);
+
+	/* Save the stop position */
+	emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition);
+
+	wavexferbuf->stopposition -= wave_out->voice->params.start;
+
+	/* Refer to voicemgr.c, CA is not started at zero.  We need to take this into account. */
+	position = wavexferbuf->stopposition * wavexferbuf->bytespersample;
+
+	if (!wavexferbuf->is_16bit)
+		samples <<= 1;
+
+	if (wavexferbuf->is_stereo)
+		samples <<= 1;
+
+	samples -= 4;
+
+	if (position >= samples * (wavexferbuf->is_16bit + 1))
+		position -= samples * (wavexferbuf->is_16bit + 1);
+	else
+		position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1);
+
+	wavexferbuf->stopposition = position / wavexferbuf->bytespersample;
+
+	DPD(2, "position is %x\n", wavexferbuf->stopposition);
+
+	wave_out->state = CARDWAVE_STATE_STOPPED;
+	wave_out->setpos = 0;
+	wave_out->position = 0;
+
+	return;
+}
+
+void emu10k1_waveout_getxfersize(struct wave_out *wave_out, u32 * size, u32 * pending, u32 * curpos)
+{
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+
+	/* Get position of current address, this is in no. of bytes in play buffer */
+	emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, curpos);
+
+	if ((*curpos > wavexferbuf->silence_xferpos)
+	    || ((*curpos == wavexferbuf->silence_xferpos)
+		&& (wave_out->state == CARDWAVE_STATE_STARTED))
+	    || ((*curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0)
+		&& (wave_out->state == CARDWAVE_STATE_STOPPED))) {
+		*size = *curpos - wavexferbuf->silence_xferpos;
+		*pending = wavexferbuf->xferbufsize - *size;
+	} else {
+		*pending = wavexferbuf->silence_xferpos - *curpos;
+		*size = wavexferbuf->xferbufsize - *pending;
+	}
+
+	if (wavexferbuf->silence_xferpos != wavexferbuf->xferpos) {
+		if (*pending < wave_out->callbacksize) {
+			wave_out->fill_silence = 2;
+			*pending = 0;
+			*size = wavexferbuf->xferbufsize;
+			wavexferbuf->xferpos = *curpos;
+		} else {
+			if (wave_out->fill_silence == 2) {
+				*pending = 0;
+				*size = wavexferbuf->xferbufsize;
+				wavexferbuf->xferpos = *curpos;
+			} else {
+				*pending -= wave_out->callbacksize;
+				*size += wave_out->callbacksize;
+			}
+		}
+	} else {
+		if (*pending < wave_out->callbacksize)
+			wave_out->fill_silence = 1;
+		else
+			wave_out->fill_silence = 0;
+	}
+
+	return;
+}
+
+static void copy_block(u32 dst, u8 * src, u32 len, void **pt)
+{
+	int i, j, k;
+
+	i = dst / PAGE_SIZE;
+	j = dst % PAGE_SIZE;
+	k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
+	copy_from_user(pt[i] + j, src, k);
+	len -= k;
+	while (len >= PAGE_SIZE) {
+		copy_from_user(pt[++i], src + k, PAGE_SIZE);
+		k += PAGE_SIZE;
+		len -= PAGE_SIZE;
+	}
+	copy_from_user(pt[++i], src + k, len);
+
+	return;
+}
+
+static void fill_block(u32 dst, u8 val, u32 len, void **pt)
+{
+	int i, j, k;
+
+	i = dst / PAGE_SIZE;
+	j = dst % PAGE_SIZE;
+	k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
+	memset(pt[i] + j, val, k);
+	len -= k;
+	while (len >= PAGE_SIZE) {
+		memset(pt[++i], val, PAGE_SIZE);
+		len -= PAGE_SIZE;
+	}
+	memset(pt[++i], val, len);
+
+	return;
+}
+
+void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size)
+{
+	struct wave_out *wave_out = woinst->wave_out;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	u32 sizetocopy, sizetocopy_now, start;
+	unsigned long flags;
+
+	sizetocopy = min(wavexferbuf->xferbufsize, *size);
+	*size = sizetocopy;
+
+	if (!sizetocopy)
+		return;
+
+	spin_lock_irqsave(&woinst->lock, flags);
+
+	sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos;
+
+	start = wavexferbuf->xferpos;
+
+	if (sizetocopy > sizetocopy_now) {
+		sizetocopy -= sizetocopy_now;
+		wavexferbuf->xferpos = sizetocopy;
+		wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
+		spin_unlock_irqrestore(&woinst->lock, flags);
+
+		copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer);
+		copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer);
+	} else {
+		if (sizetocopy == sizetocopy_now)
+			wavexferbuf->xferpos = 0;
+		else
+			wavexferbuf->xferpos += sizetocopy;
+
+		wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
+		spin_unlock_irqrestore(&woinst->lock, flags);
+
+		copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer);
+	}
+
+	return;
+}
+
+void emu10k1_waveout_fillsilence(struct woinst *woinst)
+{
+	struct wave_out *wave_out = woinst->wave_out;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	u16 filldata;
+	u32 sizetocopy, sizetocopy_now, start;
+	unsigned long flags;
+
+	sizetocopy = wave_out->callbacksize;
+
+	if (wave_out->wave_fmt.bitsperchannel == 8)
+		filldata = 0x8080;
+	else
+		filldata = 0x0000;
+
+	spin_lock_irqsave(&woinst->lock, flags);
+
+	sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos;
+	start = wavexferbuf->silence_xferpos;
+
+	if (sizetocopy > sizetocopy_now) {
+		sizetocopy -= sizetocopy_now;
+		wavexferbuf->silence_xferpos = sizetocopy;
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer);
+		fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer);
+	} else {
+		if (sizetocopy == sizetocopy_now)
+			wavexferbuf->silence_xferpos = 0;
+		else
+			wavexferbuf->silence_xferpos += sizetocopy;
+
+		spin_unlock_irqrestore(&woinst->lock, flags);
+
+		fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer);
+	}
+
+	return;
+}
+
+/* get the specified control value of the wave device. */
+
+int emu10k1_waveout_getcontrol(struct wave_out *wave_out, u32 ctrl_id, u32 * value)
+{
+	switch (ctrl_id) {
+	case WAVECURPOS:
+		/* There is no actual start yet */
+		if (wave_out->state == CARDWAVE_STATE_STOPPED) {
+			if (wave_out->setpos)
+				*value = wave_out->position;
+			else
+				*value = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample;
+		} else {
+			emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, value);
+
+			*value -= wave_out->voice->params.start;
+
+			/* Get number of bytes in play buffer per channel.
+			 * If 8 bit mode is enabled, this needs to be changed. */
+			{
+				u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1);
+
+				*value *= wave_out->wavexferbuf->bytespersample;
+
+				/* Refer to voicemgr.c, CA is not started at zero.
+				 * We need to take this into account. */
+
+				samples -= 4 * (wave_out->wavexferbuf->is_16bit + 1);
+
+				if (*value >= samples)
+					*value -= samples;
+				else
+					*value += wave_out->wavexferbuf->xferbufsize - samples;
+			}
+		}
+
+		break;
+	default:
+		return CTSTATUS_ERROR;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.h linux/drivers/sound/emu10k1/cardwo.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/cardwo.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,118 @@
+/*     
+ **********************************************************************
+ *     cardwo.h -- header file for card wave out functions
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _CARDWO_H
+#define _CARDWO_H
+
+#include "icardwav.h"
+
+struct wave_xferbuf 
+{
+	u32     xferpos;
+	u32     silence_xferpos;
+	u32     xferbufsize;     /* transfer buffer size */
+	u32     numpages;        /* number of pages in transfer buffer */
+	void    **xferbuffer;    /* pointer to the transfer buffer */
+	int     is_stereo;
+	int     is_16bit;
+	int	bytespersample;
+	u32     stopposition;
+};
+
+struct wave_out
+{
+    u32             state;
+    struct emu_voice *voice;
+    int             emupageindex;
+    struct emu_timer *timer;
+    struct wave_xferbuf *wavexferbuf;
+    void 	    **pagetable;
+    u32             callbacksize;
+    u32             localvol;
+    u32             localreverb;
+    u32             localchorus;
+    u32             globalvolFactor;
+    u32             globalreverbFactor;
+    u32             globalchorusFactor;
+    int             setpos;
+    u32             position;
+    struct wave_format      wave_fmt;
+    int             fill_silence;
+};
+
+/* setting this to other than a power of two
+   may break some applications */
+#define WAVEOUT_MAXBUFSIZE          32768 
+#define WAVEOUT_MINBUFSIZE	    64
+
+#define WAVEOUT_DEFAULTFRAGLEN      100 /* Time to play a fragment in ms (latency) */
+#define WAVEOUT_DEFAULTBUFLEN       1000 /* Time to play the entire buffer in ms */
+
+#define WAVEOUT_MINFRAGSHIFT	4
+
+struct woinst 
+{
+        struct wave_out *wave_out;
+        struct wave_format wave_fmt;
+        u16 ossfragshift;
+        u32 fragment_size;
+        u32 numfrags;
+        wait_queue_head_t wait_queue;
+        int mapped;
+        u32 total_copied;
+        u32 total_played;
+        u32 blocks;
+	u32 curpos;
+	u32 device;
+	spinlock_t lock;
+};
+
+struct emu10k1_waveout
+{
+	u32 globalvol;
+	u32 mute;
+	u32 left;
+	u32 right;
+	u32 globalreverb;
+	u32 globalchorus;
+};
+
+int emu10k1_waveout_open(struct emu10k1_wavedevice *);
+void emu10k1_waveout_close(struct emu10k1_wavedevice *);
+int emu10k1_waveout_start(struct emu10k1_wavedevice *);
+void emu10k1_waveout_stop(struct emu10k1_wavedevice *);
+void emu10k1_waveout_getxfersize(struct wave_out *, u32 *, u32 *, u32 *);
+void emu10k1_waveout_xferdata(struct woinst*, u8*, u32 *);
+void emu10k1_waveout_fillsilence(struct woinst*);
+int emu10k1_waveout_setformat(struct emu10k1_wavedevice*);
+int emu10k1_waveout_getcontrol(struct wave_out*, u32, u32 *);
+
+#endif /* _CARDWO_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.c linux/drivers/sound/emu10k1/efxmgr.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/efxmgr.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,34 @@
+
+/*     
+ **********************************************************************
+ *     sblive_fx.c
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#include "hwaccess.h"
+#include "efxmgr.h"
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.h linux/drivers/sound/emu10k1/efxmgr.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/efxmgr.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,43 @@
+/*     
+ **********************************************************************
+ *     sblive_fx.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _EFXMGR_H
+#define _EFXMGR_H
+
+#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
+
+#define OP(op, z, w, x, y) \
+        do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \
+        WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \
+        ++pc; } while (0)
+
+
+#endif /* _EFXMGR_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/emu_wrapper.h linux/drivers/sound/emu10k1/emu_wrapper.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/emu_wrapper.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/emu_wrapper.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,11 @@
+#ifndef __EMU_WRAPPER_H
+#define __EMU_WRAPPER_H
+
+#include <linux/wrapper.h>
+
+#define UP_INODE_SEM(a)
+#define DOWN_INODE_SEM(a)
+
+#define GET_INODE_STRUCT()
+
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/emuadxmg.c linux/drivers/sound/emu10k1/emuadxmg.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/emuadxmg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/emuadxmg.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,101 @@
+
+/*     
+ **********************************************************************
+ *     emuadxmg.c - Address space manager for emu10k1 driver 
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#include "hwaccess.h"
+
+/* Allocates emu address space */
+
+int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card)
+{
+	u16 *pagetable = card->emupagetable;
+	u16 index = 0;
+	u16 numpages;
+	unsigned long flags;
+
+	/* Convert bytes to pages */
+	numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0);
+
+	while (index < (MAXPAGES - RESERVED - 1)) {
+		if (pagetable[index] & 0x8000) {
+			/* This block of pages is in use, jump to the start of the next block. */
+			index += (pagetable[index] & 0x7fff);
+		} else {
+			/* Found free block */
+			if (pagetable[index] >= numpages) {
+				spin_lock_irqsave(&card->lock, flags);
+
+				/* Block is large enough */
+
+				/* If free block is larger than the block requested
+				 * then adjust the size of the block remaining */
+				if (pagetable[index] > numpages)
+					pagetable[index + numpages] = pagetable[index] - numpages;
+
+				pagetable[index] = (numpages | 0x8000);	/* Mark block as used */
+
+				spin_unlock_irqrestore(&card->lock, flags);
+
+				return index;
+			} else {
+				/* Block too small, jump to the start of the next block */
+				index += pagetable[index];
+			}
+		}
+	}
+
+	return -1;
+}
+
+/* Frees a previously allocated emu address space. */
+
+void emu10k1_addxmgr_free(struct emu10k1_card *card, int index)
+{
+	u16 *pagetable = card->emupagetable;
+	u16 origsize = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	if (pagetable[index] & 0x8000) {
+		/* Block is allocated - mark block as free */
+		origsize = pagetable[index] & 0x7fff;
+		pagetable[index] = origsize;
+
+		/* If next block is free, we concat both blocks */
+		if (!(pagetable[index + origsize] & 0x8000))
+			pagetable[index] += pagetable[index + origsize] & 0x7fff;
+	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.c linux/drivers/sound/emu10k1/hwaccess.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/hwaccess.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,430 @@
+
+/*
+ **********************************************************************
+ *     hwaccess.c -- Hardware access layer
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     December 9, 1999     Jon Taylor      rewrote the I/O subsystem
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "icardmid.h"
+
+/*************************************************************************
+* Function : srToPitch                                                   *
+* Input    : sampleRate - sampling rate                                  *
+* Return   : pitch value                                                 *
+* About    : convert sampling rate to pitch                              *
+* Note     : for 8010, sampling rate is at 48kHz, this function should   *
+*            be changed.                                                 *
+*************************************************************************/
+u32 srToPitch(u32 sampleRate)
+{
+	int i;
+
+	/* FIXME: These tables should be defined in a headerfile */
+	static u32 logMagTable[128] = {
+		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
+		0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
+		0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
+		0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
+		0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
+		0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
+		0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
+		0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
+		0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
+		0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
+		0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
+		0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
+		0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
+		0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
+		0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
+		0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
+	};
+
+	static char logSlopeTable[128] = {
+		0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
+		0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
+		0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
+		0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
+		0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
+		0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
+		0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
+		0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
+		0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
+		0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
+		0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
+		0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
+		0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
+		0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
+		0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
+		0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
+	};
+
+	if (sampleRate == 0)
+		return (0);	/* Bail out if no leading "1" */
+
+	sampleRate *= 11185;	/* Scale 48000 to 0x20002380 */
+
+	for (i = 31; i > 0; i--) {
+		if (sampleRate & 0x80000000) {	/* Detect leading "1" */
+			return (u32) (((s32) (i - 15) << 20) +
+				      logMagTable[0x7f & (sampleRate >> 24)] +
+				      (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]);
+		}
+		sampleRate = sampleRate << 1;
+	}
+
+	DPF(2, "srToPitch: BUG!\n");
+	return 0;		/* Should never reach this point */
+}
+
+/* Returns an attenuation based upon a cumulative volume value */
+
+/* Algorithm calculates 0x200 - 0x10 log2 (input) */
+u8 sumVolumeToAttenuation(u32 value)
+{
+	u16 count = 16;
+	s16 ans;
+
+	if (value == 0)
+		return 0xFF;
+
+	/* Find first SET bit. This is the integer part of the value */
+	while ((value & 0x10000) == 0) {
+		value <<= 1;
+		count--;
+	}
+
+	/* The REST of the data is the fractional part. */
+	ans = (s16) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12)));
+	if (ans > 0xFF)
+		ans = 0xFF;
+
+	return (u8) ans;
+}
+
+/*******************************************
+* write/read PCI function 0 registers      *
+********************************************/
+void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	outl(data, card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return;
+}
+
+void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data)
+{
+	unsigned long flags;
+
+	data &= mask;
+
+	spin_lock_irqsave(&card->lock, flags);
+	data |= inl(card->iobase + reg) & ~mask;
+	outl(data, card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return;
+}
+
+u32 sblive_readfn0(struct emu10k1_card * card, u8 reg)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	val = inl(card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
+	return val;
+}
+
+u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	val = inl(card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
+	return val & mask;
+}
+
+/************************************************************************
+* write/read Emu10k1 pointer-offset register set, accessed through      *
+*  the PTR and DATA registers                                           *
+*************************************************************************/
+void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
+{
+	u32 regptr;
+	unsigned long flags;
+
+	regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
+
+	if (reg & 0xff000000) {
+		u32 mask;
+		u8 size, offset;
+
+		size = (reg >> 24) & 0x3f;
+		offset = (reg >> 16) & 0x1f;
+		mask = ((1 << size) - 1) << offset;
+		data = (data << offset) & mask;
+
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		data |= inl(card->iobase + DATA) & ~mask;
+		outl(data, card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
+	} else {
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		outl(data, card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
+	}
+
+	return;
+}
+
+u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
+{
+	u32 regptr, val;
+	unsigned long flags;
+
+	regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
+
+	if (reg & 0xff000000) {
+		u32 mask;
+		u8 size, offset;
+
+		size = (reg >> 24) & 0x3f;
+		offset = (reg >> 16) & 0x1f;
+		mask = ((1 << size) - 1) << offset;
+
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		val = inl(card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
+
+		return (val & mask) >> offset;
+	} else {
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		val = inl(card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
+
+		return val;
+	}
+}
+
+void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
+{
+	/* Voice interrupt */
+	if (voicenum >= 32)
+		sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1);
+	else
+		sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1);
+
+	return;
+}
+
+void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
+{
+	/* Voice interrupt */
+	if (voicenum >= 32)
+		sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
+	else
+		sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
+
+	return;
+}
+
+static void sblive_wcwait(struct emu10k1_card *card, u32 wait)
+{
+	volatile unsigned uCount;
+	u32 newtime = 0, curtime;
+
+	curtime = READ_FN0(card, WC_SAMPLECOUNTER);
+	while (wait--) {
+		uCount = 0;
+		while (uCount++ < TIMEOUT) {
+			newtime = READ_FN0(card, WC_SAMPLECOUNTER);
+			if (newtime != curtime)
+				break;
+		}
+
+		if (uCount >= TIMEOUT)
+			break;
+
+		curtime = newtime;
+	}
+}
+
+int sblive_readac97(struct emu10k1_card *card, u8 index, u16 * data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	outb(index, card->mixeraddx + 2);
+	*data = inw(card->mixeraddx);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	outb(index, card->mixeraddx + 2);
+	outw(data, card->mixeraddx);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask)
+{
+	u16 temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	outb(index, card->mixeraddx + 2);
+	temp = inw(card->mixeraddx);
+	temp &= ~mask;
+	data &= mask;
+	temp |= data;
+	outw(temp, card->mixeraddx);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/*********************************************************
+*            MPU access functions                        *
+**********************************************************/
+
+int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
+		outb(data, card->iobase + MUDATA);
+		ret = CTSTATUS_SUCCESS;
+	} else
+		ret = CTSTATUS_BUSY;
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return ret;
+}
+
+int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
+		*data = inb(card->iobase + MUDATA);
+		ret = CTSTATUS_SUCCESS;
+	} else
+		ret = CTSTATUS_NODATA;
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return ret;
+}
+
+int emu10k1_mpu_reset(struct emu10k1_card *card)
+{
+	u8 status;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_mpu_reset()\n");
+
+	if (card->mpuacqcount == 0) {
+		spin_lock_irqsave(&card->lock, flags);
+		outb(MUCMD_RESET, card->iobase + MUCMD);
+		spin_unlock_irqrestore(&card->lock, flags);
+
+		sblive_wcwait(card, 8);
+
+		spin_lock_irqsave(&card->lock, flags);
+		outb(MUCMD_RESET, card->iobase + MUCMD);
+		spin_unlock_irqrestore(&card->lock, flags);
+
+		sblive_wcwait(card, 8);
+
+		spin_lock_irqsave(&card->lock, flags);
+		outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
+		spin_unlock_irqrestore(&card->lock, flags);
+
+		sblive_wcwait(card, 8);
+
+		spin_lock_irqsave(&card->lock, flags);
+		status = inb(card->iobase + MUDATA);
+		spin_unlock_irqrestore(&card->lock, flags);
+
+		if (status == 0xfe)
+			return CTSTATUS_SUCCESS;
+		else
+			return CTSTATUS_ERROR;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+int emu10k1_mpu_acquire(struct emu10k1_card *card)
+{
+	/* FIXME: This should be a macro */
+	++card->mpuacqcount;
+
+	return CTSTATUS_SUCCESS;
+}
+
+int emu10k1_mpu_release(struct emu10k1_card *card)
+{
+	/* FIXME: this should be a macro */
+	--card->mpuacqcount;
+
+	return CTSTATUS_SUCCESS;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.h linux/drivers/sound/emu10k1/hwaccess.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/hwaccess.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,204 @@
+/*
+ **********************************************************************
+ *     hwaccess.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date		    Author	    Summary of changes
+ *     ----		    ------	    ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _HWACCESS_H
+#define _HWACCESS_H
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <emu_wrapper.h>
+
+enum GlobalErrorCode
+{
+	CTSTATUS_SUCCESS = 0x0000,
+	CTSTATUS_ERROR,
+	CTSTATUS_NOMEMORY,
+	CTSTATUS_INUSE,
+};
+
+#define FLAGS_AVAILABLE     0x0001
+#define FLAGS_READY         0x0002
+
+#define min(x,y) ((x) < (y)) ? (x) : (y)
+
+struct memhandle
+{
+	unsigned long busaddx;
+	void *virtaddx;
+	u32 order;
+};
+
+struct memhandle *emu10k1_alloc_memphysical(u32);
+void emu10k1_free_memphysical(struct memhandle *);
+
+#define DEBUG_LEVEL 2
+
+#ifdef EMU10K1_DEBUG
+# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0)
+# define DPF(level,x)   do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0)
+#define ERROR() DPF(1,"error\n");
+#else
+# define DPD(level,x,y...) /* not debugging: nothing */
+# define DPF(level,x)
+#define ERROR()
+#endif /* EMU10K1_DEBUG */
+
+#include "8010.h"
+#include "voicemgr.h"
+
+int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
+void emu10k1_addxmgr_free(struct emu10k1_card *, int);
+
+#include "timer.h"
+#include "irqmgr.h"
+
+/* DATA STRUCTURES */
+
+struct emu10k1_card 
+{
+	struct list_head list;
+
+	struct memhandle	*virtualpagetable;
+
+	struct memhandle	*tankmem;
+	u32 tmemsize;
+	struct memhandle	*silentpage;
+
+	spinlock_t		lock;
+
+	struct voice_manager	voicemgr;
+	u16			emupagetable[MAXPAGES];
+
+	struct list_head	timers;
+	unsigned		timer_delay;
+	spinlock_t		timer_lock;
+
+	struct pci_dev		*pci_dev;
+	unsigned long           iobase;
+        unsigned long           mixeraddx;
+	u32  irq; 
+
+	unsigned long	audio1_num;
+	unsigned long	audio2_num;
+	unsigned long	mixer_num;
+	unsigned long	midi_num;
+
+	struct emu10k1_waveout	*waveout;
+	struct emu10k1_wavein	*wavein;
+	struct emu10k1_mpuout	*mpuout;
+	struct emu10k1_mpuin	*mpuin;
+
+	u16			arrwVol[SOUND_MIXER_NRDEVICES + 1];
+	/* array is used from the member 1 to save (-1) operation */
+	u32			digmix[96];
+	unsigned int		modcnt;
+	struct semaphore	open_sem;
+	mode_t			open_mode;
+	wait_queue_head_t	open_wait;
+
+	u32	    mpuacqcount;	  // Mpu acquire count
+	u32	    has_toslink;	       // TOSLink detection
+
+	u8 chiprev;                    /* Chip revision                */
+};
+
+#ifdef PRIVATE_PCM_VOLUME
+
+#define MAX_PCM_CHANNELS NUM_G 
+struct sblive_pcm_volume_rec {
+	struct files_struct *files; // identification of the same thread
+	u8 attn_l;		// attenuation for left channel
+	u8 attn_r;		// attenuation for right channel
+	u16 mixer;		// saved mixer value for return
+	u8 channel_l;		// idx of left channel
+	u8 channel_r;		// idx of right channel
+	int opened;		// counter - locks element
+};
+extern struct sblive_pcm_volume_rec sblive_pcm_volume[];
+
+#endif
+
+
+#define ENABLE 			0xffffffff
+#define DISABLE 		0x00000000
+
+#define ENV_ON			0x80
+#define ENV_OFF			0x00
+
+#define TIMEOUT 		    16384
+
+u32 srToPitch(u32);
+u8 sumVolumeToAttenuation(u32);
+
+extern struct list_head emu10k1_devs;
+
+/* Hardware Abstraction Layer access functions */
+
+#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f))
+
+#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f)
+
+void sblive_writefn0(struct emu10k1_card *, u8 , u32 );
+void sblive_wrtmskfn0(struct emu10k1_card *, u8 , u32 , u32 );
+
+u32 sblive_readfn0(struct emu10k1_card *, u8 );
+u32 sblive_rdmskfn0(struct emu10k1_card *, u8, u32 );
+
+void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 );
+u32 sblive_readptr(struct emu10k1_card *, u32 , u32 );
+
+void emu10k1_set_stop_on_loop(struct emu10k1_card *, u32);
+void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32);
+
+/* AC97 Mixer access function */
+int sblive_readac97(struct emu10k1_card *, u8, u16 *);
+int sblive_writeac97(struct emu10k1_card *, u8, u16);
+int sblive_rmwac97(struct emu10k1_card *, u8, u16, u16);
+
+/* MPU access function*/
+int emu10k1_mpu_write_data(struct emu10k1_card *, u8);
+int emu10k1_mpu_read_data(struct emu10k1_card *, u8 *);
+int emu10k1_mpu_reset(struct emu10k1_card *);
+int emu10k1_mpu_acquire(struct emu10k1_card *);
+int emu10k1_mpu_release(struct emu10k1_card *);
+
+#endif  /* _HWACCESS_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/icardmid.h linux/drivers/sound/emu10k1/icardmid.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/icardmid.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/icardmid.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,163 @@
+/*
+ **********************************************************************
+ *     isblive_mid.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _ICARDMIDI_H
+#define _ICARDMIDI_H
+
+/* MIDI defines */
+#define MIDI_DATA_FIRST                 0x00
+#define MIDI_DATA_LAST                  0x7F
+#define MIDI_STATUS_FIRST               0x80
+#define MIDI_STATUS_LAST                0xFF
+
+/* Channel status bytes */
+#define MIDI_STATUS_CHANNEL_FIRST       0x80
+#define MIDI_STATUS_CHANNEL_LAST        0xE0
+#define MIDI_STATUS_CHANNEL_MASK        0xF0
+
+/* Channel voice messages */
+#define MIDI_VOICE_NOTE_OFF             0x80
+#define MIDI_VOICE_NOTE_ON              0x90
+#define MIDI_VOICE_POLY_PRESSURE        0xA0
+#define MIDI_VOICE_CONTROL_CHANGE       0xB0
+#define MIDI_VOICE_PROGRAM_CHANGE       0xC0
+#define MIDI_VOICE_CHANNEL_PRESSURE     0xD0
+#define MIDI_VOICE_PITCH_BEND           0xE0
+
+/* Channel mode messages */
+#define MIDI_MODE_CHANNEL               MIDI_VOICE_CONTROL_CHANGE
+
+/* System status bytes */
+#define MIDI_STATUS_SYSTEM_FIRST        0xF0
+#define MIDI_STATUS_SYSTEM_LAST         0xFF
+
+/* System exclusive messages */
+#define MIDI_SYSEX_BEGIN                0xF0
+#define MIDI_SYSEX_EOX                  0xF7
+
+/* System common messages */
+#define MIDI_COMMON_TCQF                0xF1	/* Time code quarter frame  */
+#define MIDI_COMMON_SONG_POSITION       0xF2
+#define MIDI_COMMON_SONG_SELECT         0xF3
+#define MIDI_COMMON_UNDEFINED_F4        0xF4
+#define MIDI_COMMON_UNDEFINED_F5        0xF5
+#define MIDI_COMMON_TUNE_REQUEST        0xF6
+
+/* System real-time messages */
+#define MIDI_RTIME_TIMING_CLOCK         0xF8
+#define MIDI_RTIME_UNDEFINED_F9         0xF9
+#define MIDI_RTIME_START                0xFA
+#define MIDI_RTIME_CONTINUE             0xFB
+#define MIDI_RTIME_STOP                 0xFC
+#define MIDI_RTIME_UNDEFINED_FD         0xFD
+#define MIDI_RTIME_ACTIVE_SENSING       0xFE
+#define MIDI_RTIME_SYSTEM_RESET         0xFF
+
+/* Flags for flags parm of midiOutCachePatches(), midiOutCacheDrumPatches() */
+#define MIDI_CACHE_ALL                  1
+#define MIDI_CACHE_BESTFIT              2
+#define MIDI_CACHE_QUERY                3
+#define MIDI_UNCACHE                    4
+
+/* Event declarations for MPU IRQ Callbacks */
+#define ICARDMIDI_INLONGDATA            0x00000001 /* MIM_LONGDATA */
+#define ICARDMIDI_INLONGERROR           0x00000002 /* MIM_LONGERROR */
+#define ICARDMIDI_OUTLONGDATA           0x00000004 /* MOM_DONE for MPU OUT buffer */
+#define ICARDMIDI_INDATA                0x00000010 /* MIM_DATA */
+#define ICARDMIDI_INDATAERROR           0x00000020 /* MIM_ERROR */
+
+/* Declaration for flags in CARDMIDIBUFFERHDR */
+/* Make it the same as MHDR_DONE, MHDR_INQUEUE in mmsystem.h */
+#define MIDIBUF_DONE                    0x00000001
+#define MIDIBUF_INQUEUE                 0x00000004
+
+/* Declaration for msg parameter in midiCallbackFn */
+#define ICARDMIDI_OUTBUFFEROK           0x00000001
+#define ICARDMIDI_INMIDIOK              0x00000002
+
+/* Declaration for technology in struct midi_caps */
+#define MT_MIDIPORT                     0x00000001	/* In original MIDIOUTCAPS structure */
+#define MT_FMSYNTH                      0x00000004	/* In original MIDIOUTCAPS structure */
+#define MT_AWESYNTH                     0x00001000
+#define MT_PCISYNTH                     0x00002000
+#define MT_PCISYNTH64                   0x00004000
+#define CARDMIDI_AWEMASK                0x0000F000
+
+enum LocalErrorCode
+{
+        CTSTATUS_NOTENABLED = 0x7000,
+        CTSTATUS_READY,
+        CTSTATUS_BUSY,
+        CTSTATUS_DATAAVAIL,
+        CTSTATUS_NODATA,
+        CTSTATUS_NEXT_BYTE
+};
+
+/* MIDI data block header */
+struct midi_hdr
+{
+	u8 *reserved;		/* Pointer to original locked data block */
+	u32 bufferlength;	/* Length of data in data block */
+	u32 bytesrecorded;	/* Used for input only */
+	u32 user;		/* For client's use */
+	u32 flags;		/* Assorted flags (see defines) */
+	struct list_head list;	/* Reserved for driver */
+	u8 *data;		/* Second copy of first pointer */
+};
+
+/* Enumeration for SetControl */
+enum
+{
+	MIDIOBJVOLUME = 0x1,
+	MIDIQUERYACTIVEINST
+};
+
+struct midi_queue
+{
+	struct midi_queue  *next;
+	u32 qtype;            /* 0 = short message, 1 = long data */
+	u32 length;
+	u32 sizeLeft;
+	u8 *midibyte;
+	unsigned long refdata;
+};
+
+struct midi_openinfo
+{
+	u32     cbsize;
+	u32     flags;
+	unsigned long  refdata;
+	u32     streamid;
+};
+
+int emu10k1_midi_callback(unsigned long , unsigned long, unsigned long *);
+
+#endif /* _ICARDMIDI_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/icardwav.h linux/drivers/sound/emu10k1/icardwav.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/icardwav.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/icardwav.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,52 @@
+/*     
+ **********************************************************************
+ *     icardwav.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _ICARDWAV_H
+#define _ICARDWAV_H
+
+/* Enumeration for SetControl */
+enum
+{
+        WAVECURPOS = 0x10,
+};
+
+struct wave_format 
+{
+	u32 samplingrate;
+	u32 bitsperchannel;
+	u32 channels;		/* 1 = Mono, 2 = Stereo */
+};
+
+/* emu10k1_wave states */
+#define CARDWAVE_STATE_STOPPED     0x0001
+#define CARDWAVE_STATE_STARTED     0x0002
+
+#endif /* _ICARDWAV_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.c linux/drivers/sound/emu10k1/irqmgr.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/irqmgr.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,127 @@
+
+/*
+ **********************************************************************
+ *     irqmgr.c - IRQ manager for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "cardmi.h"
+#include "cardmo.h"
+#include "irqmgr.h"
+
+/* Interrupt handler */
+
+void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
+	u32 irqstatus, ptr, tmp;
+
+	if (!(irqstatus = sblive_readfn0(card, IPR)))
+		return;
+
+	DPD(4, "emu10k1_interrupt called, irq =  %u\n", irq);
+
+	/* Preserve PTR register */
+	ptr = sblive_readfn0(card, PTR);
+
+	/*
+	 ** NOTE :
+	 ** We do a 'while loop' here cos on certain machines, with both
+	 ** playback and recording going on at the same time, IRQs will
+	 ** stop coming in after a while. Checking IPND indeed shows that
+	 ** there are interrupts pending but the PIC says no IRQs pending.
+	 ** I suspect that some boards need edge-triggered IRQs but are not
+	 ** getting that condition if we don't completely clear the IPND
+	 ** (make sure no more interrupts are pending).
+	 ** - Eric
+	 */
+
+	do {
+		DPD(4, "irq status %x\n", irqstatus);
+
+		tmp = irqstatus;
+
+		if (irqstatus & IRQTYPE_TIMER) {
+			emu10k1_timer_irqhandler(card);
+			irqstatus &= ~IRQTYPE_TIMER;
+		}
+
+		if (irqstatus & IRQTYPE_MPUIN) {
+			emu10k1_mpuin_irqhandler(card);
+			irqstatus &= ~IRQTYPE_MPUIN;
+		}
+
+		if (irqstatus & IRQTYPE_MPUOUT) {
+			emu10k1_mpuout_irqhandler(card);
+			irqstatus &= ~IRQTYPE_MPUOUT;
+		}
+
+		if (irqstatus)
+			emu10k1_irq_disable(card, irqstatus);
+
+		sblive_writefn0(card, IPR, tmp);
+
+	} while ((irqstatus = sblive_readfn0(card, IPR)));
+
+	sblive_writefn0(card, PTR, ptr);
+
+	return;
+}
+
+/* Enables the specified irq service */
+
+int emu10k1_irq_enable(struct emu10k1_card *card, u32 irqtype)
+{
+	/*
+	 * TODO :
+	 * put protection here so that we don't accidentally
+	 * screw-up another cardxxx objects irqs
+	 */
+
+	DPD(4, "emu10k1_irq_enable %x\n", irqtype);
+	sblive_wrtmskfn0(card, INTE, irqtype, ENABLE);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* Disables the specified irq service */
+
+int emu10k1_irq_disable(struct emu10k1_card *card, u32 irqtype)
+{
+	/*
+	 * TODO :
+	 * put protection here so that we don't accidentally
+	 * screw-up another cardxxx objects irqs
+	 */
+
+	DPD(4, "emu10k1_irq_disable %x\n", irqtype);
+	sblive_wrtmskfn0(card, INTE, irqtype, DISABLE);
+
+	return CTSTATUS_SUCCESS;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.h linux/drivers/sound/emu10k1/irqmgr.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/irqmgr.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,59 @@
+/*
+ **********************************************************************
+ *     irq.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _IRQ_H
+#define _IRQ_H
+
+/* EMU Irq Types */
+#define IRQTYPE_PCIBUSERROR         IPR_PCIERROR
+#define IRQTYPE_MIXERBUTTON         (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
+#define IRQTYPE_VOICE               (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
+#define IRQTYPE_RECORD              (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
+#define IRQTYPE_MPUOUT              IPR_MIDITRANSBUFEMPTY
+#define IRQTYPE_MPUIN               IPR_MIDIRECVBUFEMPTY
+#define IRQTYPE_TIMER               IPR_INTERVALTIMER
+#define IRQTYPE_SPDIF               (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
+#define IRQTYPE_DSP                 IPR_FXDSP
+
+struct emu10k1_wavedevice
+{
+        struct emu10k1_card *card;
+        struct wiinst *wiinst;
+        struct woinst *woinst;
+        u16 enablebits;
+};
+
+void emu10k1_timer_irqhandler(struct emu10k1_card *);
+
+int emu10k1_irq_enable(struct emu10k1_card *, u32);
+int emu10k1_irq_disable(struct emu10k1_card *, u32);
+
+#endif /* _IRQ_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/main.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/main.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,825 @@
+
+/*
+ **********************************************************************
+ *     main.c - Creative EMU10K1 audio driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up stuff
+ *
+ **********************************************************************
+ *
+ *     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.
+ *
+ **********************************************************************
+ *
+ *      Supported devices:
+ *      /dev/dsp:     Standard /dev/dsp device, OSS-compatible
+ *      /dev/mixer:   Standard /dev/mixer device, OSS-compatible
+ *      /dev/midi:    Raw MIDI UART device, mostly OSS-compatible
+ *
+ *      Revision history:
+ *      0.1 beta Initial release
+ *      0.2 Lowered initial mixer vol. Improved on stuttering wave playback. Added MIDI UART support.
+ *      0.3 Fixed mixer routing bug, added APS, joystick support.
+ *      0.4 Added rear-channel, SPDIF support.
+ *	0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes,
+ *	    moved bh's to tasklets, moved to the new PCI driver initialization style.
+ **********************************************************************
+ */
+
+/* These are only included once per module */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "hwaccess.h"
+#include "efxmgr.h"
+#include "cardwo.h"
+#include "cardwi.h"
+#include "cardmo.h"
+#include "cardmi.h"
+#include "recmgr.h"
+
+#define DRIVER_VERSION "0.5"
+
+/* FIXME: is this right? */
+#define EMU10K1_DMA_MASK                0xffffffff	/* DMA buffer mask for pci_alloc_consist */
+
+#ifndef PCI_VENDOR_ID_CREATIVE
+#define PCI_VENDOR_ID_CREATIVE 0x1102
+#endif
+
+#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1
+#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
+#endif
+
+#define EMU10K1_EXTENT	0x20	/* 32 byte I/O space */
+
+enum {
+	EMU10K1 = 0,
+};
+
+static char *card_names[] __devinitdata = {
+	"EMU10K1",
+};
+
+static struct pci_device_id emu10k1_pci_tbl[] __initdata = {
+	{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, emu10k1_pci_tbl);
+
+/* Global var instantiation */
+
+LIST_HEAD(emu10k1_devs);
+
+extern struct file_operations emu10k1_audio_fops;
+extern struct file_operations emu10k1_mixer_fops;
+extern struct file_operations emu10k1_midi_fops;
+
+extern void emu10k1_interrupt(int, void *, struct pt_regs *s);
+extern int emu10k1_mixer_wrch(struct emu10k1_card *, unsigned int, int);
+
+static int __devinit audio_init(struct emu10k1_card *card)
+{
+	if ((card->waveout = kmalloc(sizeof(struct emu10k1_waveout), GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_waveout: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+	memset(card->waveout, 0, sizeof(struct emu10k1_waveout));
+
+	/* Assign default global volume, reverb, chorus */
+	card->waveout->globalvol = 0xffffffff;
+	card->waveout->left = 0xffff;
+	card->waveout->right = 0xffff;
+	card->waveout->mute = 0;
+	card->waveout->globalreverb = 0xffffffff;
+	card->waveout->globalchorus = 0xffffffff;
+
+	if ((card->wavein = kmalloc(sizeof(struct emu10k1_wavein), GFP_KERNEL))
+	    == NULL) {
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_wavein: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+	memset(card->wavein, 0, sizeof(struct emu10k1_wavein));
+
+	card->wavein->recsrc = WAVERECORD_AC97;
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void __devinit mixer_init(struct emu10k1_card *card)
+{
+	int count;
+	struct initvol {
+		int mixch;
+		int vol;
+	} initvol[] = {
+		{
+		SOUND_MIXER_VOLUME, 0x5050}, {
+		SOUND_MIXER_OGAIN, 0x3232}, {
+		SOUND_MIXER_SPEAKER, 0x3232}, {
+		SOUND_MIXER_PHONEIN, 0x3232}, {
+		SOUND_MIXER_MIC, 0x0000}, {
+		SOUND_MIXER_LINE, 0x0000}, {
+		SOUND_MIXER_CD, 0x3232}, {
+		SOUND_MIXER_LINE1, 0x3232}, {
+		SOUND_MIXER_LINE3, 0x3232}, {
+		SOUND_MIXER_DIGITAL1, 0x6464}, {
+		SOUND_MIXER_DIGITAL2, 0x6464}, {
+		SOUND_MIXER_PCM, 0x6464}, {
+		SOUND_MIXER_RECLEV, 0x3232}, {
+		SOUND_MIXER_TREBLE, 0x3232}, {
+		SOUND_MIXER_BASS, 0x3232}, {
+	SOUND_MIXER_LINE2, 0x4b4b}};
+
+	int initdig[] = { 0, 1, 2, 3, 6, 7, 16, 17, 18, 19, 22, 23, 64, 65, 66, 67, 70, 71,
+		84, 85
+	};
+
+	/* Reset */
+	sblive_writeac97(card, AC97_RESET, 0);
+
+#if 0
+	/* Check status word */
+	{
+		u16 reg;
+
+		sblive_readac97(card, AC97_RESET, &reg);
+		DPD(2, "RESET 0x%x\n", reg);
+		sblive_readac97(card, AC97_MASTERTONE, &reg);
+		DPD(2, "MASTER_TONE 0x%x\n", reg);
+	}
+#endif
+
+	/* Set default recording source to mic in */
+	sblive_writeac97(card, AC97_RECORDSELECT, 0);
+
+	/* Set default AC97 "PCM" volume to acceptable max */
+	//sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
+	//sblive_writeac97(card, AC97_LINE2, 0);
+
+	/* Set default volumes for all mixer channels */
+
+	for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) {
+		card->digmix[count] = 0x80000000;
+		sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0);
+	}
+
+	for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) {
+		card->digmix[initdig[count]] = 0x7fffffff;
+		sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff);
+	}
+
+	for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++) {
+		emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol);
+	}
+
+	card->modcnt = 0;	// Should this be here or in open() ?
+
+	return;
+}
+
+static int __devinit midi_init(struct emu10k1_card *card)
+{
+	if ((card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL))
+	    == NULL) {
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+
+	memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout));
+
+	card->mpuout->intr = 1;
+	card->mpuout->status = FLAGS_AVAILABLE;
+	card->mpuout->state = CARDMIDIOUT_STATE_DEFAULT;
+
+	tasklet_init(&card->mpuout->tasklet, emu10k1_mpuout_bh, (unsigned long) card);
+
+	spin_lock_init(&card->mpuout->lock);
+
+	if ((card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL)) == NULL) {
+		kfree(card->mpuout);
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+
+	memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin));
+
+	card->mpuin->status = FLAGS_AVAILABLE;
+
+	tasklet_init(&card->mpuin->tasklet, emu10k1_mpuin_bh, (unsigned long) card->mpuin);
+
+	spin_lock_init(&card->mpuin->lock);
+
+	/* Reset the MPU port */
+	if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) {
+		ERROR();
+		return CTSTATUS_ERROR;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void __devinit voice_init(struct emu10k1_card *card)
+{
+	struct voice_manager *voicemgr = &card->voicemgr;
+	struct emu_voice *voice;
+	int i;
+
+	voicemgr->card = card;
+	voicemgr->lock = SPIN_LOCK_UNLOCKED;
+
+	voice = voicemgr->voice;
+	for (i = 0; i < NUM_G; i++) {
+		voice->card = card;
+		voice->usage = VOICEMGR_USAGE_FREE;
+		voice->num = i;
+		voice->linked_voice = NULL;
+		voice++;
+	}
+
+	return;
+}
+
+static void __devinit timer_init(struct emu10k1_card *card)
+{
+	INIT_LIST_HEAD(&card->timers);
+	card->timer_delay = TIMER_STOPPED;
+	card->timer_lock = SPIN_LOCK_UNLOCKED;
+
+	return;
+}
+
+static void __devinit addxmgr_init(struct emu10k1_card *card)
+{
+	u32 count;
+
+	for (count = 0; count < MAXPAGES; count++)
+		card->emupagetable[count] = 0;
+
+	/* Mark first page as used */
+	/* This page is reserved by the driver */
+	card->emupagetable[0] = 0x8001;
+	card->emupagetable[1] = MAXPAGES - RESERVED - 1;
+
+	return;
+}
+
+static void __devinit fx_init(struct emu10k1_card *card)
+{
+	int i, j, k, l;
+	u32 pc = 0;
+
+	for (i = 0; i < 512; i++)
+		OP(6, 0x40, 0x40, 0x40, 0x40);
+
+	for (i = 0; i < 256; i++)
+		sblive_writeptr(card, FXGPREGBASE + i, 0, 0);
+
+	pc = 0;
+
+	for (j = 0; j < 2; j++) {
+
+		OP(4, 0x100, 0x40, j, 0x44);
+		OP(4, 0x101, 0x40, j + 2, 0x44);
+
+		for (i = 0; i < 6; i++) {
+			k = i * 16 + j;
+			OP(0, 0x102, 0x40, 0x110 + k, 0x100);
+			OP(0, 0x102, 0x102, 0x112 + k, 0x101);
+			OP(0, 0x102, 0x102, 0x114 + k, 0x10 + j);
+			OP(0, 0x102, 0x102, 0x116 + k, 0x12 + j);
+			OP(0, 0x102, 0x102, 0x118 + k, 0x14 + j);
+			OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j);
+			OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j);
+			OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j);
+
+			k = 0x190 + i * 8 + j * 4;
+			OP(0, 0x40, 0x40, 0x102, 0x170 + j);
+			OP(7, k + 1, k, k + 1, 0x174 + j);
+			OP(7, k, 0x102, k, 0x172 + j);
+			OP(7, k + 3, k + 2, k + 3, 0x178 + j);
+			OP(0, k + 2, 0x56, k + 2, 0x176 + j);
+			OP(6, k + 2, k + 2, k + 2, 0x40);
+
+			l = 0x1c0 + i * 8 + j * 4;
+			OP(0, 0x40, 0x40, k + 2, 0x180 + j);
+			OP(7, l + 1, l, l + 1, 0x184 + j);
+			OP(7, l, k + 2, l, 0x182 + j);
+			OP(7, l + 3, l + 2, l + 3, 0x188 + j);
+			OP(0, l + 2, 0x56, l + 2, 0x186 + j);
+			OP(4, l + 2, 0x40, l + 2, 0x46);
+
+			OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40);
+
+		}
+	}
+	sblive_writeptr(card, DBG, 0, 0);
+
+	return;
+}
+
+static int __devinit hw_init(struct emu10k1_card *card)
+{
+	int nCh;
+
+#ifdef TANKMEM
+	u32 size = 0;
+#endif
+	u32 sizeIdx = 0;
+	u32 pagecount, tmp;
+
+	/* Disable audio and lock cache */
+	sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
+
+	/* Reset recording buffers */
+	sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, MICBA, 0, 0);
+	sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, FXBA, 0, 0);
+	sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, ADCBA, 0, 0);
+
+	/* Disable channel interrupt */
+	sblive_writefn0(card, INTE, DISABLE);
+	sblive_writeptr(card, CLIEL, 0, 0);
+	sblive_writeptr(card, CLIEH, 0, 0);
+	sblive_writeptr(card, SOLEL, 0, 0);
+	sblive_writeptr(card, SOLEH, 0, 0);
+
+	/* Init envelope engine */
+	for (nCh = 0; nCh < NUM_G; nCh++) {
+		sblive_writeptr(card, DCYSUSV, nCh, ENV_OFF);
+		sblive_writeptr(card, IP, nCh, 0);
+		sblive_writeptr(card, VTFT, nCh, 0xffff);
+		sblive_writeptr(card, CVCF, nCh, 0xffff);
+		sblive_writeptr(card, PTRX, nCh, 0);
+		sblive_writeptr(card, CPF, nCh, 0);
+		sblive_writeptr(card, CCR, nCh, 0);
+
+		sblive_writeptr(card, PSST, nCh, 0);
+		sblive_writeptr(card, DSL, nCh, 0x10);
+		sblive_writeptr(card, CCCA, nCh, 0);
+		sblive_writeptr(card, Z1, nCh, 0);
+		sblive_writeptr(card, Z2, nCh, 0);
+		sblive_writeptr(card, FXRT, nCh, 0xd01c0000);
+
+		sblive_writeptr(card, ATKHLDM, nCh, 0);
+		sblive_writeptr(card, DCYSUSM, nCh, 0);
+		sblive_writeptr(card, IFATN, nCh, 0xffff);
+		sblive_writeptr(card, PEFE, nCh, 0);
+		sblive_writeptr(card, FMMOD, nCh, 0);
+		sblive_writeptr(card, TREMFRQ, nCh, 24);	/* 1 Hz */
+		sblive_writeptr(card, FM2FRQ2, nCh, 24);	/* 1 Hz */
+		sblive_writeptr(card, TEMPENV, nCh, 0);
+
+		/*** These are last so OFF prevents writing ***/
+		sblive_writeptr(card, LFOVAL2, nCh, 0);
+		sblive_writeptr(card, LFOVAL1, nCh, 0);
+		sblive_writeptr(card, ATKHLDV, nCh, 0);
+		sblive_writeptr(card, ENVVOL, nCh, 0);
+		sblive_writeptr(card, ENVVAL, nCh, 0);
+	}
+
+	/*
+	 ** Init to 0x02109204 :
+	 ** Clock accuracy    = 0     (1000ppm)
+	 ** Sample Rate       = 2     (48kHz)
+	 ** Audio Channel     = 1     (Left of 2)
+	 ** Source Number     = 0     (Unspecified)
+	 ** Generation Status = 1     (Original for Cat Code 12)
+	 ** Cat Code          = 12    (Digital Signal Mixer)
+	 ** Mode              = 0     (Mode 0)
+	 ** Emphasis          = 0     (None)
+	 ** CP                = 1     (Copyright unasserted)
+	 ** AN                = 0     (Digital audio)
+	 ** P                 = 0     (Consumer)
+	 */
+
+	/* SPDIF0 */
+	sblive_writeptr(card, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+
+	/* SPDIF1 */
+	sblive_writeptr(card, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+
+	/* SPDIF2 & SPDIF3 */
+	sblive_writeptr(card, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+
+	fx_init(card);		/* initialize effects engine */
+
+	card->tankmem = NULL;
+
+#ifdef TANKMEM
+	size = TMEMSIZE;
+	sizeIdx = TMEMSIZEREG;
+	while (size > 16384) {
+		if ((card->tankmem = emu10k1_alloc_memphysical(size)) != NULL)
+			break;
+
+		size /= 2;
+		sizeIdx -= 1;
+	}
+
+	if (card->tankmem == NULL) {
+		card->tmemsize = 0;
+		return CTSTATUS_ERROR;
+	}
+
+	card->tmemsize = size;
+#else				/* !TANKMEM */
+	card->tmemsize = 0;
+#endif				/* TANKMEM */
+
+	if ((card->virtualpagetable = emu10k1_alloc_memphysical((MAXPAGES - RESERVED) * sizeof(u32))) == NULL) {
+		ERROR();
+		emu10k1_free_memphysical(card->tankmem);
+		return CTSTATUS_ERROR;
+	}
+
+	if ((card->silentpage = emu10k1_alloc_memphysical(EMUPAGESIZE)) == NULL) {
+		ERROR();
+		emu10k1_free_memphysical(card->tankmem);
+		emu10k1_free_memphysical(card->virtualpagetable);
+		return CTSTATUS_ERROR;
+	} else
+		memset(card->silentpage->virtaddx, 0, EMUPAGESIZE);
+
+	for (pagecount = 0; pagecount < (MAXPAGES - RESERVED); pagecount++)
+
+		((u32 *) card->virtualpagetable->virtaddx)[pagecount] = (card->silentpage->busaddx * 2) | pagecount;
+
+	/* Init page table & tank memory base register */
+	sblive_writeptr(card, PTB, 0, card->virtualpagetable->busaddx);
+#ifdef TANKMEM
+	sblive_writeptr(card, TCB, 0, card->tankmem->busaddx);
+#else
+	sblive_writeptr(card, TCB, 0, 0);
+#endif
+	sblive_writeptr(card, TCBS, 0, sizeIdx);
+
+	for (nCh = 0; nCh < NUM_G; nCh++) {
+		sblive_writeptr(card, MAPA, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+		sblive_writeptr(card, MAPB, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+	}
+
+	/* Hokay, now enable the AUD bit */
+	/* Enable Audio = 1 */
+	/* Mute Disable Audio = 0 */
+	/* Lock Tank Memory = 1 */
+	/* Lock Sound Memory = 0 */
+	/* Auto Mute = 1 */
+
+	sblive_rmwac97(card, AC97_MASTERVOLUME, 0x8000, 0x8000);
+
+	sblive_writeac97(card, AC97_MASTERVOLUME, 0);
+	sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
+
+	sblive_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
+
+	/* TOSLink detection */
+	card->has_toslink = 0;
+
+	tmp = sblive_readfn0(card, HCFG);
+	if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
+		sblive_writefn0(card, HCFG, tmp | 0x800);
+
+		udelay(512);
+
+		if (tmp != (sblive_readfn0(card, HCFG) & ~0x800)) {
+			card->has_toslink = 1;
+			sblive_writefn0(card, HCFG, tmp);
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+static int __devinit emu10k1_init(struct emu10k1_card *card)
+{
+	/* Init Card */
+	if (hw_init(card) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	voice_init(card);
+	timer_init(card);
+	addxmgr_init(card);
+
+	DPD(2, "  hw control register -> %x\n", sblive_readfn0(card, HCFG));
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void __devexit audio_exit(struct emu10k1_card *card)
+{
+	kfree(card->waveout);
+	kfree(card->wavein);
+	return;
+}
+
+static void __devexit midi_exit(struct emu10k1_card *card)
+{
+	tasklet_unlock_wait(&card->mpuout->tasklet);
+	kfree(card->mpuout);
+
+	tasklet_unlock_wait(&card->mpuin->tasklet);
+	kfree(card->mpuin);
+
+	return;
+}
+
+static void __devexit emu10k1_exit(struct emu10k1_card *card)
+{
+	int ch;
+
+	sblive_writefn0(card, INTE, DISABLE);
+
+	/** Shutdown the chip **/
+	for (ch = 0; ch < NUM_G; ch++)
+		sblive_writeptr(card, DCYSUSV, ch, ENV_OFF);
+
+	for (ch = 0; ch < NUM_G; ch++) {
+		sblive_writeptr(card, VTFT, ch, 0);
+		sblive_writeptr(card, CVCF, ch, 0);
+		sblive_writeptr(card, PTRX, ch, 0);
+		sblive_writeptr(card, CPF, ch, 0);
+	}
+
+	/* Reset recording buffers */
+	sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, MICBA, 0, 0);
+	sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, FXBA, 0, 0);
+	sblive_writeptr(card, FXWC, 0, 0);
+	sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, ADCBA, 0, 0);
+	sblive_writeptr(card, TCBS, 0, TCBS_BUFFSIZE_16K);
+	sblive_writeptr(card, TCB, 0, 0);
+	sblive_writeptr(card, DBG, 0, 0x8000);
+
+	/* Disable channel interrupt */
+	sblive_writeptr(card, CLIEL, 0, 0);
+	sblive_writeptr(card, CLIEH, 0, 0);
+	sblive_writeptr(card, SOLEL, 0, 0);
+	sblive_writeptr(card, SOLEH, 0, 0);
+
+	/* Disable audio and lock cache */
+	sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
+	sblive_writeptr(card, PTB, 0, 0);
+
+	emu10k1_free_memphysical(card->silentpage);
+	emu10k1_free_memphysical(card->virtualpagetable);
+#ifdef TANKMEM
+	emu10k1_free_memphysical(card->tankmem);
+#endif
+	return;
+}
+
+/* Driver initialization routine */
+static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+{
+	struct emu10k1_card *card;
+
+	if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "emu10k1: out of memory\n");
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(struct emu10k1_card));
+
+#if LINUX_VERSION_CODE > 0x020320
+	if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) {
+		printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n");
+		kfree(card);
+		return -ENODEV;
+	}
+
+	if (pci_enable_device(pci_dev)) {
+		printk(KERN_ERR "emu10k1: couldn't enable device\n");
+		kfree(card);
+		return -ENODEV;
+	}
+
+	pci_set_master(pci_dev);
+
+	card->iobase = pci_dev->resource[0].start;
+
+	if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) {
+		printk(KERN_ERR "emu10k1: IO space in use\n");
+		kfree(card);
+		return -ENODEV;
+	}
+	pci_dev->driver_data = card;
+	pci_dev->dma_mask = EMU10K1_DMA_MASK;
+#else
+	pci_set_master(pci_dev);
+
+	card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+
+	if (check_region(card->iobase, EMU10K1_EXTENT)) {
+		printk(KERN_ERR "emu10k1: IO space in use\n");
+		kfree(card);
+		return -ENODEV;
+	}
+
+	request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]);
+#endif
+	card->irq = pci_dev->irq;
+	card->pci_dev = pci_dev;
+
+	/* Reserve IRQ Line */
+	if (request_irq(card->irq, emu10k1_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) {
+		printk(KERN_ERR "emu10k1: IRQ in use\n");
+		goto err_irq;
+	}
+
+	pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev);
+
+	printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq);
+
+	spin_lock_init(&card->lock);
+	card->mixeraddx = card->iobase + AC97DATA;
+	init_MUTEX(&card->open_sem);
+	card->open_mode = 0;
+	init_waitqueue_head(&card->open_wait);
+
+	/* Register devices */
+	if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register first audio device!\n");
+		goto err_dev0;
+	}
+
+	if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register second audio device!\n");
+		goto err_dev1;
+	}
+
+	if ((card->mixer_num = register_sound_mixer(&emu10k1_mixer_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register mixer device!\n");
+		goto err_dev2;
+	}
+
+	if ((card->midi_num = register_sound_midi(&emu10k1_midi_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register midi device!\n");
+		goto err_dev3;
+	}
+
+	if (emu10k1_init(card) != CTSTATUS_SUCCESS) {
+		printk(KERN_ERR "emu10k1: cannot initialize device!\n");
+		goto err_emu10k1_init;
+	}
+
+	if (audio_init(card) != CTSTATUS_SUCCESS) {
+		printk(KERN_ERR "emu10k1: cannot initialize audio!\n");
+		goto err_audio_init;
+	}
+
+	if (midi_init(card) != CTSTATUS_SUCCESS) {
+		printk(KERN_ERR "emu10k1: cannot initialize midi!\n");
+		goto err_midi_init;
+	}
+
+	mixer_init(card);
+
+	DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize);
+
+	list_add(&card->list, &emu10k1_devs);
+
+	return 0;
+
+      err_midi_init:
+	audio_exit(card);
+
+      err_audio_init:
+	emu10k1_exit(card);
+
+      err_emu10k1_init:
+	unregister_sound_midi(card->midi_num);
+
+      err_dev3:
+	unregister_sound_mixer(card->mixer_num);
+
+      err_dev2:
+	unregister_sound_dsp(card->audio2_num);
+
+      err_dev1:
+	unregister_sound_dsp(card->audio1_num);
+
+      err_dev0:
+	free_irq(card->irq, card);
+
+      err_irq:
+	release_region(card->iobase, EMU10K1_EXTENT);
+	kfree(card);
+
+	return -ENODEV;
+}
+
+static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
+{
+#if LINUX_VERSION_CODE > 0x020320
+	struct emu10k1_card *card = pci_dev->driver_data;
+#else
+	struct emu10k1_card *card = list_entry(emu10k1_devs.next, struct emu10k1_card, list);
+#endif
+	midi_exit(card);
+	audio_exit(card);
+	emu10k1_exit(card);
+
+	unregister_sound_midi(card->midi_num);
+	unregister_sound_mixer(card->mixer_num);
+	unregister_sound_dsp(card->audio2_num);
+	unregister_sound_dsp(card->audio1_num);
+
+	free_irq(card->irq, card);
+	release_region(card->iobase, EMU10K1_EXTENT);
+
+	list_del(&card->list);
+
+	kfree(card);
+	return;
+}
+
+MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)");
+MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd.");
+
+static struct pci_driver emu10k1_pci_driver __initdata = {
+	name:"emu10k1",
+	id_table:emu10k1_pci_tbl,
+	probe:emu10k1_probe,
+	remove:emu10k1_remove,
+};
+
+#if LINUX_VERSION_CODE > 0x020320
+static int __init emu10k1_init_module(void)
+{
+	printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+
+	return pci_module_init(&emu10k1_pci_driver);
+}
+
+static void __exit emu10k1_cleanup_module(void)
+{
+	pci_unregister_driver(&emu10k1_pci_driver);
+	return;
+}
+
+#else
+
+static int __init emu10k1_init_module(void)
+{
+	struct pci_dev *dev = NULL;
+	const struct pci_device_id *pci_id = emu10k1_pci_driver.id_table;
+
+	printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+
+	if (!pci_present())
+		return -ENODEV;
+
+	while (pci_id->vendor) {
+		while ((dev = pci_find_device(pci_id->vendor, pci_id->device, dev)))
+			emu10k1_probe(dev, pci_id);
+
+		pci_id++;
+	}
+	return 0;
+}
+
+static void __exit emu10k1_cleanup_module(void)
+{
+	struct emu10k1_card *card;
+
+	while (!list_empty(&emu10k1_devs)) {
+		card = list_entry(emu10k1_devs.next, struct emu10k1_card, list);
+
+		emu10k1_remove(card->pci_dev);
+	}
+
+	return;
+}
+
+#endif
+
+module_init(emu10k1_init_module);
+module_exit(emu10k1_cleanup_module);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/midi.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,446 @@
+
+/*
+ **********************************************************************
+ *     midi.c - /dev/midi interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+#include "hwaccess.h"
+#include "cardmo.h"
+#include "cardmi.h"
+#include "midi.h"
+
+static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED;
+
+static void init_midi_hdr(struct midi_hdr *midihdr)
+{
+	midihdr->bufferlength = MIDIIN_BUFLEN;
+	midihdr->bytesrecorded = 0;
+	midihdr->flags = 0;
+}
+
+static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr)
+{
+	struct midi_hdr *midihdr;
+
+	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) {
+		ERROR();
+		return -EINVAL;
+	}
+
+	init_midi_hdr(midihdr);
+
+	if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) {
+		ERROR();
+		kfree(midihdr);
+		return CTSTATUS_ERROR;
+	}
+
+	if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) {
+		ERROR();
+		kfree(midihdr->data);
+		kfree(midihdr);
+		return CTSTATUS_ERROR;
+	}
+
+	*midihdrptr = midihdr;
+	list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
+
+	return CTSTATUS_SUCCESS;
+}
+
+static int emu10k1_midi_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct emu10k1_card *card;
+	struct emu10k1_mididevice *midi_dev;
+	struct list_head *entry;
+
+	DPF(2, "emu10k1_midi_open()\n");
+
+	/* Check for correct device to open */
+	list_for_each(entry, &emu10k1_devs) {
+		card = list_entry(entry, struct emu10k1_card, list);
+
+		if (card->midi_num == minor)
+			break;
+	}
+
+	if (entry == &emu10k1_devs)
+		return -ENODEV;
+
+	MOD_INC_USE_COUNT;
+
+	/* Wait for device to become free */
+	down(&card->open_sem);
+	while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+		if (file->f_flags & O_NONBLOCK) {
+			up(&card->open_sem);
+			MOD_DEC_USE_COUNT;
+			return -EBUSY;
+		}
+
+		up(&card->open_sem);
+		interruptible_sleep_on(&card->open_wait);
+
+		if (signal_pending(current)) {
+			MOD_DEC_USE_COUNT;
+			return -ERESTARTSYS;
+		}
+
+		down(&card->open_sem);
+	}
+
+	if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -EINVAL;
+	}
+
+	midi_dev->card = card;
+	midi_dev->mistate = MIDIIN_STATE_STOPPED;
+	init_waitqueue_head(&midi_dev->oWait);
+	init_waitqueue_head(&midi_dev->iWait);
+	midi_dev->ird = 0;
+	midi_dev->iwr = 0;
+	midi_dev->icnt = 0;
+	INIT_LIST_HEAD(&midi_dev->mid_hdrs);
+
+	if (file->f_mode & FMODE_READ) {
+		struct midi_openinfo dsCardMidiOpenInfo;
+		struct midi_hdr *midihdr1;
+		struct midi_hdr *midihdr2;
+
+		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
+
+		if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo)
+		    != CTSTATUS_SUCCESS) {
+			ERROR();
+			kfree(midi_dev);
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+
+		/* Add two buffers to receive sysex buffer */
+		if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) {
+			kfree(midi_dev);
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+
+		if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) {
+			list_del(&midihdr1->list);
+			kfree(midihdr1->data);
+			kfree(midihdr1);
+			kfree(midi_dev);
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		struct midi_openinfo dsCardMidiOpenInfo;
+
+		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
+
+		if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo)
+		    != CTSTATUS_SUCCESS) {
+			ERROR();
+			kfree(midi_dev);
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+	}
+
+	file->private_data = (void *) midi_dev;
+
+	card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+
+	up(&card->open_sem);
+
+	return 0;
+}
+
+static int emu10k1_midi_release(struct inode *inode, struct file *file)
+{
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
+	struct emu10k1_card *card = midi_dev->card;
+
+	DPF(2, "emu10k1_midi_release()\n");
+
+	if (file->f_mode & FMODE_WRITE) {
+		if (!(file->f_flags & O_NONBLOCK)) {
+
+			while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) {
+				DPF(4, "Cannot close - buffers not empty\n");
+
+				interruptible_sleep_on(&midi_dev->oWait);
+
+			}
+		}
+
+		emu10k1_mpuout_close(card);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		struct midi_hdr *midihdr;
+
+		if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
+			emu10k1_mpuin_stop(card);
+			midi_dev->mistate = MIDIIN_STATE_STOPPED;
+		}
+
+		emu10k1_mpuin_reset(card);
+		emu10k1_mpuin_close(card);
+
+		while (!list_empty(&midi_dev->mid_hdrs)) {
+			midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list);
+
+			list_del(midi_dev->mid_hdrs.next);
+			kfree(midihdr->data);
+			kfree(midihdr);
+		}
+	}
+
+	kfree(midi_dev);
+
+	down(&card->open_sem);
+	card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
+	up(&card->open_sem);
+	wake_up_interruptible(&card->open_wait);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, loff_t * pos)
+{
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
+	ssize_t ret = 0;
+	u16 cnt;
+	unsigned long flags;
+
+	DPD(4, "emu10k1_midi_read(), count %x\n", (u32) count);
+
+	if (pos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+
+	if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
+		if (emu10k1_mpuin_start(midi_dev->card)
+		    != CTSTATUS_SUCCESS) {
+			ERROR();
+			return -EINVAL;
+		}
+
+		midi_dev->mistate = MIDIIN_STATE_STARTED;
+	}
+
+	while (count > 0) {
+		cnt = MIDIIN_BUFLEN - midi_dev->ird;
+
+		spin_lock_irqsave(&midi_spinlock, flags);
+
+		if (midi_dev->icnt < cnt)
+			cnt = midi_dev->icnt;
+
+		spin_unlock_irqrestore(&midi_spinlock, flags);
+
+		if (cnt > count)
+			cnt = count;
+
+		if (cnt <= 0) {
+			if (file->f_flags & O_NONBLOCK)
+				return ret ? ret : -EAGAIN;
+			DPF(2, " Go to sleep...\n");
+
+			interruptible_sleep_on(&midi_dev->iWait);
+
+			if (signal_pending(current))
+				return ret ? ret : -ERESTARTSYS;
+
+			continue;
+		}
+
+		if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) {
+			ERROR();
+			return ret ? ret : -EFAULT;
+		}
+
+		midi_dev->ird += cnt;
+		midi_dev->ird %= MIDIIN_BUFLEN;
+
+		spin_lock_irqsave(&midi_spinlock, flags);
+
+		midi_dev->icnt -= cnt;
+
+		spin_unlock_irqrestore(&midi_spinlock, flags);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if (midi_dev->icnt == 0)
+			break;
+	}
+
+	return ret;
+}
+
+static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t count, loff_t * pos)
+{
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
+	struct midi_hdr *midihdr;
+	ssize_t ret = 0;
+	unsigned long flags;
+
+	DPD(4, "emu10k1_midi_write(), count=%x\n", (u32) count);
+
+	if (pos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+
+	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL)
+		return -EINVAL;
+
+	midihdr->bufferlength = count;
+	midihdr->bytesrecorded = 0;
+	midihdr->flags = 0;
+
+	if ((midihdr->data = (u8 *) kmalloc(count, GFP_KERNEL)) == NULL) {
+		ERROR();
+		kfree(midihdr);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(midihdr->data, buffer, count)) {
+		kfree(midihdr->data);
+		kfree(midihdr);
+		return ret ? ret : -EFAULT;
+	}
+
+	spin_lock_irqsave(&midi_spinlock, flags);
+
+	if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) {
+		ERROR();
+		kfree(midihdr->data);
+		kfree(midihdr);
+		spin_unlock_irqrestore(&midi_spinlock, flags);
+		return -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&midi_spinlock, flags);
+
+	return count;
+}
+
+static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+	DPF(4, "emu10k1_midi_poll() called\n");
+	return 0;
+}
+
+int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
+{
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata;
+	struct midi_hdr *midihdr = NULL;
+	unsigned long flags;
+	int i;
+
+	DPF(4, "emu10k1_midi_callback()\n");
+
+	spin_lock_irqsave(&midi_spinlock, flags);
+
+	switch (msg) {
+	case ICARDMIDI_OUTLONGDATA:
+		midihdr = (struct midi_hdr *) pmsg[2];
+
+		kfree(midihdr->data);
+		kfree(midihdr);
+		wake_up_interruptible(&midi_dev->oWait);
+
+		break;
+
+	case ICARDMIDI_INLONGDATA:
+		midihdr = (struct midi_hdr *) pmsg[2];
+
+		for (i = 0; i < midihdr->bytesrecorded; i++) {
+			midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i];
+			midi_dev->iwr %= MIDIIN_BUFLEN;
+		}
+
+		midi_dev->icnt += midihdr->bytesrecorded;
+
+		if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
+			init_midi_hdr(midihdr);
+			emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr);
+			wake_up_interruptible(&midi_dev->iWait);
+		}
+		break;
+
+	case ICARDMIDI_INDATA:
+		{
+			u8 *pBuf = (u8 *) & pmsg[1];
+			u16 bytesvalid = pmsg[2];
+
+			for (i = 0; i < bytesvalid; i++) {
+				midi_dev->iBuf[midi_dev->iwr++] = pBuf[i];
+				midi_dev->iwr %= MIDIIN_BUFLEN;
+			}
+
+			midi_dev->icnt += bytesvalid;
+		}
+
+		wake_up_interruptible(&midi_dev->iWait);
+		break;
+
+	default:		/* Unknown message */
+		return CTSTATUS_ERROR;
+	}
+
+	spin_unlock_irqrestore(&midi_spinlock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* MIDI file operations */
+struct file_operations emu10k1_midi_fops = {
+	read:emu10k1_midi_read,
+	write:emu10k1_midi_write,
+	poll:emu10k1_midi_poll,
+	open:emu10k1_midi_open,
+	release:emu10k1_midi_release,
+};
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.h linux/drivers/sound/emu10k1/midi.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/midi.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,55 @@
+/*     
+ **********************************************************************
+ *     midi.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */ 
+
+#ifndef _MIDI_H
+#define _MIDI_H
+
+#define FMODE_MIDI_SHIFT 3
+#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)
+#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+
+#define MIDIIN_STATE_STARTED 0x00000001
+#define MIDIIN_STATE_STOPPED 0x00000002
+
+#define MIDIIN_BUFLEN 1024
+
+struct emu10k1_mididevice
+{
+	struct emu10k1_card *card;
+	u32 mistate;
+	wait_queue_head_t oWait;
+	wait_queue_head_t iWait;
+	s8 iBuf[MIDIIN_BUFLEN];
+	u16 ird, iwr, icnt;
+	struct list_head mid_hdrs;
+};
+
+#endif /* _MIDI_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/mixer.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/mixer.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,824 @@
+
+/*
+ **********************************************************************
+ *     mixer.c - /dev/mixer interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ *     This program uses some code from es1371.c, Copyright 1998-1999
+ *     Thomas Sailer
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up stuff
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#define __NO_VERSION__		/* Kernel version only defined once */
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+#include "hwaccess.h"
+
+#define AC97_PESSIMISTIC
+#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+#define vol_to_hw_5(swvol) (31 - (((swvol) * 31) / 100))
+#define vol_to_hw_4(swvol) (15 - (((swvol) * 15) / 100))
+
+#define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31)
+#define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15)
+
+#ifdef PRIVATE_PCM_VOLUME
+struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS];
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#ifdef hweight32
+#undef hweight32
+#endif
+
+extern __inline__ unsigned int hweight32(unsigned int w)
+{
+	unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+	res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+	return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+/* Mapping arrays */
+static const unsigned int recsrc[] = {
+	SOUND_MASK_MIC,
+	SOUND_MASK_CD,
+	SOUND_MASK_VIDEO,
+	SOUND_MASK_LINE1,
+	SOUND_MASK_LINE,
+	SOUND_MASK_VOLUME,
+	SOUND_MASK_OGAIN,	/* Used to be PHONEOUT */
+	SOUND_MASK_PHONEIN,
+	SOUND_MASK_TREBLE,
+	SOUND_MASK_BASS,
+	SOUND_MASK_MONITOR,
+	SOUND_MASK_PCM,
+};
+
+static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = {
+	/* 5 bit stereo */
+	[SOUND_MIXER_LINE] = AC97_LINEINVOLUME,
+	[SOUND_MIXER_CD] = AC97_CDVOLUME,
+	[SOUND_MIXER_VIDEO] = AC97_VIDEOVOLUME,
+	[SOUND_MIXER_LINE1] = AC97_AUXVOLUME,
+
+/*	[SOUND_MIXER_PCM] = AC97_PCMOUTVOLUME, */
+	/* 5 bit stereo, setting 6th bit equal to maximum attenuation */
+
+/*	[SOUND_MIXER_VOLUME] = AC97_MASTERVOLUME, */
+	[SOUND_MIXER_PHONEOUT] = AC97_HEADPHONEVOLUME,
+	/* 5 bit mono, setting 6th bit equal to maximum attenuation */
+	[SOUND_MIXER_OGAIN] = AC97_MASTERVOLUMEMONO,
+	/* 5 bit mono */
+	[SOUND_MIXER_PHONEIN] = AC97_PHONEVOLUME,
+	/* 4 bit mono but shifted by 1 */
+	[SOUND_MIXER_SPEAKER] = AC97_PCBEEPVOLUME,
+	/* 5 bit mono, 7th bit = preamp */
+	[SOUND_MIXER_MIC] = AC97_MICVOLUME,
+	/* 4 bit stereo */
+	[SOUND_MIXER_RECLEV] = AC97_RECORDGAIN,
+	/* 4 bit mono */
+	[SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC,
+	/* test code */
+	[SOUND_MIXER_BASS] = AC97_GENERALPUPOSE,
+	[SOUND_MIXER_TREBLE] = AC97_MASTERTONE,
+	[SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME,
+	[SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME
+};
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+#define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
+
+/* FIXME: mixer_rdch() is broken. */
+
+static int mixer_rdch(struct emu10k1_card *card, unsigned int ch, int *arg)
+{
+	u16 reg;
+	int j;
+	int nL, nR;
+
+	switch (ch) {
+	case SOUND_MIXER_LINE:
+	case SOUND_MIXER_CD:
+	case SOUND_MIXER_VIDEO:
+	case SOUND_MIXER_LINE1:
+	case SOUND_MIXER_PCM:
+	case SOUND_MIXER_VOLUME:
+		sblive_readac97(card, volreg[ch], &reg);
+		nL = ((~(reg >> 8) & 0x1f) * 100) / 32;
+		nR = (~(reg & 0x1f) * 100) / 32;
+		DPD(2, "mixer_rdch: l=%d, r=%d\n", nL, nR);
+		return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
+
+	case SOUND_MIXER_OGAIN:
+	case SOUND_MIXER_PHONEIN:
+		sblive_readac97(card, volreg[ch], &reg);
+		return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101, (int *) arg);
+
+	case SOUND_MIXER_SPEAKER:
+		sblive_readac97(card, volreg[ch], &reg);
+		return put_user(reg & 0x8000 ? 0 : ~((reg >> 1) & 0xf) * 0x64 / 0x10 * 0x101, (int *) arg);
+
+	case SOUND_MIXER_MIC:
+		sblive_readac97(card, volreg[ch], &reg);
+		return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101 + ((reg & 0x40) ? 0x1e1e : 0), (int *) arg);
+
+	case SOUND_MIXER_RECLEV:
+		sblive_readac97(card, volreg[ch], &reg);
+		nL = ((~(reg >> 8) & 0x1f) * 100) / 16;
+		nR = (~(reg & 0x1f) * 100) / 16;
+		return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
+
+	case SOUND_MIXER_TREBLE:
+	case SOUND_MIXER_BASS:
+		return put_user(0x0000, (int *) arg);
+	default:
+		return -EINVAL;
+	}
+}
+
+#endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+
+static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = {
+	/* 5 bit stereo */
+	[SOUND_MIXER_LINE] = 1,
+	[SOUND_MIXER_CD] = 2,
+	[SOUND_MIXER_VIDEO] = 3,
+	[SOUND_MIXER_LINE1] = 4,
+	[SOUND_MIXER_PCM] = 5,
+	/* 6 bit stereo */
+	[SOUND_MIXER_VOLUME] = 6,
+	[SOUND_MIXER_PHONEOUT] = 7,
+	/* 6 bit mono */
+	[SOUND_MIXER_OGAIN] = 8,
+	[SOUND_MIXER_PHONEIN] = 9,
+	/* 4 bit mono but shifted by 1 */
+	[SOUND_MIXER_SPEAKER] = 10,
+	/* 6 bit mono + preamp */
+	[SOUND_MIXER_MIC] = 11,
+	/* 4 bit stereo */
+	[SOUND_MIXER_RECLEV] = 12,
+	/* 4 bit mono */
+	[SOUND_MIXER_IGAIN] = 13,
+	[SOUND_MIXER_TREBLE] = 14,
+	[SOUND_MIXER_BASS] = 15,
+	[SOUND_MIXER_LINE2] = 16,
+	[SOUND_MIXER_LINE3] = 17,
+	[SOUND_MIXER_DIGITAL1] = 18,
+	[SOUND_MIXER_DIGITAL2] = 19
+};
+
+u32 bass_table[41][5] = {
+	{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
+	{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
+	{ 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
+	{ 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
+	{ 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
+	{ 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
+	{ 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
+	{ 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
+	{ 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
+	{ 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
+	{ 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
+	{ 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
+	{ 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
+	{ 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
+	{ 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
+	{ 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
+	{ 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
+	{ 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
+	{ 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
+	{ 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
+	{ 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
+	{ 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
+	{ 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
+	{ 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
+	{ 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
+	{ 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
+	{ 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
+	{ 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
+	{ 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
+	{ 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
+	{ 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
+	{ 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
+	{ 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
+	{ 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
+	{ 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
+	{ 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
+	{ 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
+	{ 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
+	{ 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
+	{ 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
+	{ 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
+};
+
+u32 treble_table[41][5] = {
+	{ 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
+	{ 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
+	{ 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
+	{ 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
+	{ 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
+	{ 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
+	{ 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
+	{ 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
+	{ 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
+	{ 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
+	{ 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
+	{ 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
+	{ 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
+	{ 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
+	{ 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
+	{ 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
+	{ 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
+	{ 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
+	{ 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
+	{ 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
+	{ 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
+	{ 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
+	{ 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
+	{ 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
+	{ 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
+	{ 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
+	{ 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
+	{ 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
+	{ 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
+	{ 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
+	{ 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
+	{ 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
+	{ 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
+	{ 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
+	{ 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
+	{ 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
+	{ 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
+	{ 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
+	{ 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
+	{ 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
+	{ 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
+};
+
+static void set_bass(struct emu10k1_card *card, int l, int r)
+{
+	int i;
+
+	l = (l * 40 + 50) / 100;
+	r = (r * 40 + 50) / 100;
+	for (i = 0; i < 5; i++) {
+		sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2), 0, bass_table[l][i]);
+		sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2) + 1, 0, bass_table[r][i]);
+	}
+}
+
+static void set_treble(struct emu10k1_card *card, int l, int r)
+{
+	int i;
+
+	l = (l * 40 + 50) / 100;
+	r = (r * 40 + 50) / 100;
+	for (i = 0; i < 5; i++) {
+		sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, treble_table[l][i]);
+		sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, treble_table[r][i]);
+	}
+}
+
+u32 db_table[101] = {
+	0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
+	0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
+	0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
+	0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
+	0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
+	0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
+	0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
+	0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
+	0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
+	0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
+	0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
+	0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
+	0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
+	0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
+	0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
+	0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
+	0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
+	0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
+	0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
+	0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
+	0x7fffffff,
+};
+
+static void update_digital(struct emu10k1_card *card)
+{
+	int i, k, l1, r1, l2, r2, l3, r3, l4, r4;
+	u64 j;
+
+	i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]];
+	l1 = (i & 0xff);
+	r1 = ((i >> 8) & 0xff);
+	i = card->arrwVol[volidx[SOUND_MIXER_LINE3]];
+	l2 = i & 0xff;
+	r2 = (i >> 8) & 0xff;
+
+	i = card->arrwVol[volidx[SOUND_MIXER_PCM]];
+	l3 = i & 0xff;
+	r3 = (i >> 8) & 0xff;
+
+	i = card->arrwVol[volidx[SOUND_MIXER_DIGITAL1]];
+	l4 = i & 0xff;
+	r4 = (i >> 8) & 0xff;
+
+	i = (r1 * r2) / 50;
+	if (r2 > 50)
+		r2 = 2 * r1 - i;
+	else {
+		r2 = r1;
+		r1 = i;
+	}
+
+	i = (l1 * l2) / 50;
+	if (l2 > 50)
+		l2 = 2 * l1 - i;
+	else {
+		l2 = l1;
+		l1 = i;
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (card->digmix[i] != 0x80000000) {
+			if ((i >= 0) && (i < 4))
+				j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]);
+			else if ((i == 6) || (i == 7))
+				j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]);
+			else
+				j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31;
+			card->digmix[i] = j >> 31;
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
+		}
+	}
+
+	for (i = 64; i < 80; i++) {
+		if (card->digmix[i] != 0x80000000) {
+			if ((i >= 64) && (i < 68))
+				j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]);
+			else if ((i == 70) || (i == 71))
+				j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]);
+			else
+				j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31;
+			card->digmix[i] = j >> 31;
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
+		}
+	}
+
+	for (i = 16; i <= 80; i += 16) {
+		if (i != 64) {
+			for (k = 0; k < 4; k++)
+				if (card->digmix[i + k] != 0x80000000) {
+					card->digmix[i + k] = db_table[l3];
+					sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]);
+				}
+			if (card->digmix[i + 6] != 0x80000000) {
+				card->digmix[i + 6] = db_table[l4];
+				sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]);
+			}
+			if (card->digmix[i + 7] != 0x80000000) {
+				card->digmix[i + 7] = db_table[r4];
+				sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]);
+			}
+		}
+	}
+
+}
+
+#ifdef PRIVATE_PCM_VOLUME
+
+/* calc & set attenuation factor for given channel */
+static int set_pcm_attn(struct emu10k1_card *card, int ch, int l)
+{
+#ifndef PCMLEVEL
+#define PCMLEVEL 140		// almost silence
+#endif
+	int vol = IFATN_ATTENUATION_MASK;	// silence
+
+	if (l > 0)
+		vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100);
+	sblive_writeptr(card, IFATN, ch, IFATN_FILTERCUTOFF_MASK | vol);
+	DPD(2, "SOUND_MIXER_PCM: channel:%d  level:%d  attn:%d\n", ch, l, vol);
+
+	return vol;
+#undef PCMLEVEL
+}
+
+/* update value of local PCM volume level (using channel attenuation)
+ *
+ * return 1: in case its local change
+ *        0: if the current process doesn't have entry in table
+ *	     (it means this process have not opened audio (mixer usually)
+ */
+static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1)
+{
+	int i;
+	int mixer = (r1 << 8) | l1;
+
+	for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+		if (sblive_pcm_volume[i].files == current->files) {
+			sblive_pcm_volume[i].mixer = mixer;
+			if (sblive_pcm_volume[i].opened) {
+				if (sblive_pcm_volume[i].channel_r < NUM_G) {
+					if (sblive_pcm_volume[i].channel_l < NUM_G)
+						sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1);
+					sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
+				} else {
+					// mono voice
+					if (sblive_pcm_volume[i].channel_l < NUM_G)
+						sblive_pcm_volume[i].attn_l =
+						    set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1);
+					// to correctly handle mono voice here we would need
+					// to go into stereo mode and move the voice to the right & left
+					// looks a bit overcomlicated...
+				}
+
+			}
+			return 1;
+		}
+	}
+	if (i == MAX_PCM_CHANNELS)
+		card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
+
+	return 0;
+}
+#endif
+
+int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val)
+{
+	int i;
+	unsigned l1, r1;
+	u16 wval;
+
+	l1 = val & 0xff;
+	r1 = (val >> 8) & 0xff;
+	if (l1 > 100)
+		l1 = 100;
+	if (r1 > 100)
+		r1 = 100;
+
+	DPD(4, "emu10k1_mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1);
+
+	if (!volidx[ch])
+		return -EINVAL;
+#ifdef PRIVATE_PCM_VOLUME
+	if (ch != SOUND_MIXER_PCM)
+#endif
+		card->arrwVol[volidx[ch]] = (r1 << 8) | l1;
+
+	switch (ch) {
+	case SOUND_MIXER_VOLUME:
+	case SOUND_MIXER_DIGITAL1:
+	case SOUND_MIXER_LINE3:
+		DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
+		update_digital(card);
+		return 0;
+	case SOUND_MIXER_PCM:
+		DPF(4, "SOUND_MIXER_PCM\n");
+#ifdef PRIVATE_PCM_VOLUME
+		if (update_pcm_attn(card, l1, r1))
+			return 0;
+#endif
+		update_digital(card);
+		return 0;
+	case SOUND_MIXER_DIGITAL2:
+	case SOUND_MIXER_LINE2:
+	case SOUND_MIXER_LINE1:
+	case SOUND_MIXER_LINE:
+	case SOUND_MIXER_CD:
+		DPD(4, "SOUND_MIXER_%s:\n",
+		    (ch == SOUND_MIXER_LINE1) ? "LINE1" :
+		    (ch == SOUND_MIXER_LINE2) ? "LINE2" : (ch == SOUND_MIXER_LINE) ? "LINE" : (ch == SOUND_MIXER_DIGITAL2) ? "DIGITAL2" : "CD");
+		wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100);
+		if (wval == 0x2020)
+			wval = 0x8000;
+		else
+			wval -= ((wval & 0x2020) / 0x20);
+		sblive_writeac97(card, volreg[ch], wval);
+		return 0;
+
+	case SOUND_MIXER_OGAIN:
+	case SOUND_MIXER_PHONEIN:
+		DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_PHONEIN) ? "PHONEIN" : "OGAIN");
+		sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100);
+		return 0;
+
+	case SOUND_MIXER_SPEAKER:
+		DPF(4, "SOUND_MIXER_SPEAKER:\n");
+		sblive_writeac97(card, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1);
+		return 0;
+
+	case SOUND_MIXER_MIC:
+		DPF(4, "SOUND_MIXER_MIC:\n");
+		i = 0;
+		if (l1 >= 30)
+			// 20dB / (34.5dB + 12dB + 20dB) * 100 = 30
+		{
+			l1 -= 30;
+			i = 0x40;
+		}
+		sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i));
+		return 0;
+
+	case SOUND_MIXER_RECLEV:
+		DPF(4, "SOUND_MIXER_RECLEV:\n");
+
+		wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100);
+		if (wval == 0)
+			wval = 0x8000;
+		else {
+			if (wval & 0xff)
+				wval--;
+			if (wval & 0xff00)
+				wval -= 0x0100;
+		}
+		sblive_writeac97(card, volreg[ch], wval);
+		return 0;
+
+	case SOUND_MIXER_TREBLE:
+		DPF(4, "SOUND_MIXER_TREBLE:\n");
+		set_treble(card, l1, r1);
+		return 0;
+
+	case SOUND_MIXER_BASS:
+		DPF(4, "SOUND_MIXER_BASS:\n");
+		set_bass(card, l1, r1);
+		return 0;
+
+	default:
+		DPF(2, "Got unknown SOUND_MIXER ioctl\n");
+		return -EINVAL;
+	}
+}
+
+static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin)
+{
+	DPF(2, "sblive_mixer_llseek() called\n");
+	return -ESPIPE;
+}
+
+/* Mixer file operations */
+
+/* FIXME: Do we need spinlocks in here? */
+static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	static const char id[] = "SBLive";
+	static const char name[] = "Creative SBLive";
+	int i, val;
+	struct emu10k1_card *card = (struct emu10k1_card *) file->private_data;
+	u16 reg;
+
+	switch (cmd) {
+
+	case SOUND_MIXER_INFO:{
+			mixer_info info;
+
+			DPF(4, "SOUND_MIXER_INFO\n");
+
+			strncpy(info.id, id, sizeof(info.id));
+			strncpy(info.name, name, sizeof(info.name));
+
+			info.modify_counter = card->modcnt;
+			if (copy_to_user((void *) arg, &info, sizeof(info)))
+				return -EFAULT;
+
+			return 0;
+		}
+		break;
+	case SOUND_OLD_MIXER_INFO:{
+			_old_mixer_info info;
+
+			DPF(4, "SOUND_OLD_MIXER_INFO\n");
+
+			strncpy(info.id, id, sizeof(info.id));
+			strncpy(info.name, name, sizeof(info.name));
+
+			if (copy_to_user((void *) arg, &info, sizeof(info)))
+				return -EFAULT;
+
+			return 0;
+		}
+		break;
+
+	case OSS_GETVERSION:
+		DPF(4, "OSS_GETVERSION\n");
+		return put_user(SOUND_VERSION, (int *) arg);
+		break;
+
+	case SOUND_MIXER_PRIVATE1:
+		DPF(4, "SOUND_MIXER_PRIVATE1");
+
+		if (copy_to_user((void *) arg, card->digmix, sizeof(card->digmix)))
+			return -EFAULT;
+
+		return 0;
+
+		break;
+	case SOUND_MIXER_PRIVATE2:
+		DPF(4, "SOUND_MIXER_PRIVATE2");
+
+		if (copy_from_user(card->digmix, (void *) arg, sizeof(card->digmix)))
+			return -EFAULT;
+
+		for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++)
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]);
+		return 0;
+
+		break;
+
+	default:
+		break;
+	}
+
+	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 */
+			DPF(2, "SOUND_MIXER_READ_RECSRC\n");
+			sblive_readac97(card, AC97_RECORDSELECT, &reg);
+			return put_user(recsrc[reg & 7], (int *) arg);
+
+		case SOUND_MIXER_DEVMASK:	/* Arg contains a bit for each supported device */
+			DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+					SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+					SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+					SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+					SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+					SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+					SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | 
+					SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
+		case SOUND_MIXER_RECMASK:	/* Arg contains a bit for each supported recording source */
+			DPF(2, "SOUND_MIXER_READ_RECMASK\n");
+			return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
+					SOUND_MASK_LINE1 | SOUND_MASK_LINE | 
+					SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | 
+					SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR | 
+					SOUND_MASK_PCM, (int *) arg);
+
+		case SOUND_MIXER_STEREODEVS:	/* Mixer channels supporting stereo */
+			DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
+			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+					SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+					SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+					SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+					SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
+					SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | 
+					SOUND_MASK_LINE2, (int *) arg);
+
+		case SOUND_MIXER_CAPS:
+			DPF(2, "SOUND_MIXER_READ_CAPS\n");
+			return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
+
+#ifdef PRIVATE_PCM_VOLUME
+		case SOUND_MIXER_PCM:
+			// needs to be before default: !!
+			{
+				int i;
+
+				for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+					if (sblive_pcm_volume[i].files == current->files) {
+						return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
+					}
+				}
+			}
+#endif
+		default:
+			i = _IOC_NR(cmd);
+			DPD(4, "SOUND_MIXER_READ(%d)\n", i);
+			if (i >= SOUND_MIXER_NRDEVICES)
+				return -EINVAL;
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+			return mixer_rdch(card, i, (int *) arg);
+#else				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+			if (!volidx[i])
+				return -EINVAL;
+			return put_user(card->arrwVol[volidx[i]], (int *) arg);
+
+#endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+		}
+	}
+	/* End of _IOC_READ */
+	if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
+		return -EINVAL;
+
+	/* _IOC_WRITE */
+	card->modcnt++;
+
+	switch (_IOC_NR(cmd)) {
+	case SOUND_MIXER_RECSRC:	/* Arg contains a bit for each recording source */
+		DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		i = hweight32(val);
+		if (i == 0)
+			return 0;	/*val = mixer_recmask(s); */
+		else if (i > 1) {
+			sblive_readac97(card, AC97_RECORDSELECT, &reg);
+			val &= ~recsrc[reg & 7];
+		}
+
+		for (i = 0; i < 8; i++) {
+			if (val & recsrc[i]) {
+				DPD(2, "Selecting record source to be 0x%04x\n", 0x0101 * i);
+				sblive_writeac97(card, AC97_RECORDSELECT, 0x0101 * i);
+				return 0;
+			}
+		}
+		return 0;
+
+	default:
+		i = _IOC_NR(cmd);
+		DPD(4, "SOUND_MIXER_WRITE(%d)\n", i);
+
+		if (i >= SOUND_MIXER_NRDEVICES)
+			return -EINVAL;
+		get_user_ret(val, (int *) arg, -EFAULT);
+		if (emu10k1_mixer_wrch(card, i, val))
+			return -EINVAL;
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+		return mixer_rdch(card, i, (int *) arg);
+#else				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+		return put_user(card->arrwVol[volidx[i]], (int *) arg);
+#endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+
+	}
+}
+
+static int emu10k1_mixer_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct emu10k1_card *card;
+	struct list_head *entry;
+
+	DPF(4, "emu10k1_mixer_open()\n");
+
+	list_for_each(entry, &emu10k1_devs) {
+		card = list_entry(entry, struct emu10k1_card, list);
+
+		if (card->mixer_num == minor)
+			break;
+	}
+
+	if (entry == &emu10k1_devs)
+		return -ENODEV;
+
+	MOD_INC_USE_COUNT;
+
+	file->private_data = card;
+	return 0;
+}
+
+static int emu10k1_mixer_release(struct inode *inode, struct file *file)
+{
+	DPF(3, "emu10k1_mixer_release()\n");
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+struct file_operations emu10k1_mixer_fops = {
+	llseek:emu10k1_mixer_llseek,
+	ioctl:emu10k1_mixer_ioctl,
+	open:emu10k1_mixer_open,
+	release:emu10k1_mixer_release,
+};
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/osutils.c linux/drivers/sound/emu10k1/osutils.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/osutils.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/osutils.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,91 @@
+
+/*
+ **********************************************************************
+ *     osutils.c - OS Services layer for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+
+struct memhandle *emu10k1_alloc_memphysical(u32 size)
+{
+	struct memhandle *handle;
+	u32 reqpage, order;
+
+	if ((handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL)) == NULL)
+		return handle;
+
+	DPD(3, "kmalloc: [%p]\n", handle);
+
+	order = 0;
+	reqpage = size / PAGE_SIZE;
+
+	if (size % PAGE_SIZE)
+		reqpage++;
+
+	if (reqpage != 0) {
+		reqpage--;
+		while (reqpage > 0) {
+			reqpage >>= 1;
+			order++;
+		}
+	}
+
+	if ((handle->virtaddx = (void *) __get_free_pages(GFP_KERNEL, order)) == NULL) {
+		kfree(handle);
+
+		DPD(3, "kfree: [%p]\n", handle);
+		return (void *) NULL;
+	}
+
+	/* in linux, we can directly access physical address, don't need to do
+	 * phys_to_virt.
+	 * In linux kernel 2.0.36, virt_to_bus does nothing, get_free_pages
+	 * returns physical address. But in kernel 2.2.1 upwards,
+	 * get_free_pages returns virtual address, we need to convert it
+	 * to physical address. Then this physical address can be used to
+	 * program hardware registers. */
+	handle->busaddx = virt_to_bus(handle->virtaddx);
+	handle->order = order;
+
+	DPD(3, "__get_free_pages: [%p] %lx\n", handle->virtaddx, handle->busaddx);
+
+	return handle;
+}
+
+void emu10k1_free_memphysical(struct memhandle *handle)
+{
+	free_pages((unsigned long) handle->virtaddx, handle->order);
+	kfree(handle);
+
+	DPD(3, "free_pages: [%p]\n", handle->virtaddx);
+	DPD(3, "kfree: [%p]\n", handle);
+
+	return;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.c linux/drivers/sound/emu10k1/recmgr.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/recmgr.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,139 @@
+
+/*
+ **********************************************************************
+ *     recmgr.c -- Recording manager for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "recmgr.h"
+
+void emu10k1_start_record(struct record *rec_ptr)
+{
+	struct emu10k1_card *hw_ptr = rec_ptr->card;
+
+	DPF(2, "emu10k1_start_record()\n");
+	DPD(2, "bus addx: %lx\n", rec_ptr->busaddx);
+
+	sblive_writeptr(hw_ptr, rec_ptr->bufaddrreg, 0, rec_ptr->busaddx);
+	sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, rec_ptr->bufsize);
+
+	if (rec_ptr->adcctl)
+		sblive_writeptr(hw_ptr, ADCCR, 0, rec_ptr->adcctl);
+
+	return;
+}
+
+void emu10k1_stop_record(struct record *rec_ptr)
+{
+	struct emu10k1_card *hw_ptr = rec_ptr->card;
+
+	DPF(2, "emu10k1_stop_record()\n");
+
+	/* Disable record transfer */
+	if (rec_ptr->adcctl)
+		sblive_writeptr(hw_ptr, ADCCR, 0, 0);
+
+	sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, ADCBS_BUFSIZE_NONE);
+
+	return;
+}
+
+void emu10k1_set_record_src(struct record *rec_ptr, u8 recsrc)
+{
+	DPF(2, "emu10k1_set_record_src()\n");
+
+	switch (recsrc) {
+
+	case WAVERECORD_AC97:
+		DPF(2, "recording source: AC97\n");
+		rec_ptr->bufsizereg = ADCBS;
+		rec_ptr->bufaddrreg = ADCBA;
+		rec_ptr->bufidxreg = ADCIDX_IDX;
+
+		switch (rec_ptr->samplingrate) {
+		case 0xBB80:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_48;
+			break;
+		case 0xAC44:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_44;
+			break;
+		case 0x7D00:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_32;
+			break;
+		case 0x5DC0:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_24;
+			break;
+		case 0x5622:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_22;
+			break;
+		case 0x3E80:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_16;
+			break;
+		case 0x2B11:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_11;
+			break;
+		case 0x1F40:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_8;
+			break;
+		default:
+			break;
+		}
+
+		rec_ptr->adcctl |= ADCCR_LCHANENABLE;
+
+		if (rec_ptr->is_stereo)
+			rec_ptr->adcctl |= ADCCR_RCHANENABLE;
+
+		//      rec_ptr->fxwc = 0;
+
+		break;
+
+	case WAVERECORD_MIC:
+		DPF(2, "recording source: MIC\n");
+		rec_ptr->bufsizereg = MICBS;
+		rec_ptr->bufaddrreg = MICBA;
+		rec_ptr->bufidxreg = MICIDX_IDX;
+		rec_ptr->adcctl = 0;
+		//      rec_ptr->fxwc = 0;
+		break;
+
+	case WAVERECORD_FX:
+		DPF(2, "recording source: FX\n");
+		rec_ptr->bufsizereg = FXBS;
+		rec_ptr->bufaddrreg = FXBA;
+		rec_ptr->bufidxreg = FXIDX_IDX;
+		rec_ptr->adcctl = 0;
+		//      rec_ptr->fxwc = 0x000ffff;
+		break;
+	default:
+		break;
+	}
+
+	return;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.h linux/drivers/sound/emu10k1/recmgr.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/recmgr.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,62 @@
+/*     
+ **********************************************************************
+ *     recmgr.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _RECORDMGR_H
+#define _RECORDMGR_H
+
+struct record 
+{
+	struct emu10k1_card *card;
+	u8 *recbuffer;
+	u32 recpos;
+	int is_stereo;
+	int is_16bit;
+	u32 recbufsize;
+	u32 bufsize;
+	u32 bufsizereg;
+	u32 bufaddrreg;
+	u32 bufidxreg;
+	u32 adcctl;
+	unsigned long busaddx;
+	u32 samplingrate;
+};
+
+/* Recording resources */
+#define WAVERECORD_AC97		0x01
+#define WAVERECORD_MIC		0x02
+#define WAVERECORD_FX		0x03
+
+void emu10k1_start_record(struct record *);
+void emu10k1_stop_record(struct record *);
+void emu10k1_set_record_src(struct record *, u8);
+
+
+#endif /* _RECORDMGR_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.c linux/drivers/sound/emu10k1/timer.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/timer.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,176 @@
+
+/*
+ **********************************************************************
+ *     timer.c
+ *     Copyright (C) 1999, 2000 Creative Labs, inc.
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This 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.
+ *
+ **********************************************************************
+ */
+
+/* 3/6/2000	Improved support for different timer delays  Rui Sousa */
+
+/* 4/3/2000	Implemented timer list using list.h 	     Rui Sousa */
+
+#include "hwaccess.h"
+
+/* Try to schedule only once per fragment */
+
+void emu10k1_timer_irqhandler(struct emu10k1_card *card)
+{
+	struct emu_timer *t;
+	struct list_head *entry;
+
+	spin_lock(&card->timer_lock);
+
+	list_for_each(entry, &card->timers) {
+		t = list_entry(entry, struct emu_timer, list);
+
+		if (t->active) {
+			t->count++;
+			if (t->count == t->count_max) {
+				t->count = 0;
+				tasklet_hi_schedule(&t->tasklet);
+			}
+		}
+	}
+
+	spin_unlock(&card->timer_lock);
+
+	return;
+}
+
+struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) (unsigned long), unsigned long data, u32 delay)
+{
+	struct emu_timer *timer;
+	struct emu_timer *t;
+	struct list_head *entry;
+	unsigned long flags;
+
+	if ((timer = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL)) == NULL)
+		return timer;
+
+	if (delay < 5)
+		delay = 5;
+
+	timer->delay = delay;
+	tasklet_init(&timer->tasklet, func, data);
+	timer->active = 0;
+
+	spin_lock_irqsave(&card->timer_lock, flags);
+
+	timer->count_max = timer->delay / (card->timer_delay < 1024 ? card->timer_delay : 1024);
+	timer->count = timer->count_max - 1;
+
+	list_add(&timer->list, &card->timers);
+
+	if (card->timer_delay > delay) {
+		if (card->timer_delay == TIMER_STOPPED)
+			emu10k1_irq_enable(card, INTE_INTERVALTIMERENB);
+
+		card->timer_delay = delay;
+		delay = (delay < 1024 ? delay : 1024);
+
+		WRITE_FN0(card, TIMER_RATE, delay);
+
+		list_for_each(entry, &card->timers) {
+			t = list_entry(entry, struct emu_timer, list);
+
+			t->count_max = t->delay / delay;
+			/* don't want to think much, just force scheduling 
+			   on the next interrupt */
+			t->count = t->count_max - 1;
+		}
+
+		DPD(2, "timer rate --> %u\n", delay);
+	}
+
+	spin_unlock_irqrestore(&card->timer_lock, flags);
+
+	return timer;
+}
+
+void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer)
+{
+	struct emu_timer *t;
+	struct list_head *entry;
+	u32 delay = TIMER_STOPPED;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->timer_lock, flags);
+
+	list_del(&timer->list);
+
+	list_for_each(entry, &card->timers) {
+		t = list_entry(entry, struct emu_timer, list);
+
+		if (t->delay < delay)
+			delay = t->delay;
+	}
+
+	if (card->timer_delay != delay) {
+		card->timer_delay = delay;
+
+		if (delay == TIMER_STOPPED)
+			emu10k1_irq_disable(card, INTE_INTERVALTIMERENB);
+		else {
+			delay = (delay < 1024 ? delay : 1024);
+
+			WRITE_FN0(card, TIMER_RATE, delay);
+
+			list_for_each(entry, &card->timers) {
+				t = list_entry(entry, struct emu_timer, list);
+
+				t->count_max = t->delay / delay;
+				t->count = t->count_max - 1;
+			}
+		}
+
+		DPD(2, "timer rate --> %u\n", delay);
+	}
+
+	spin_unlock_irqrestore(&card->timer_lock, flags);
+
+	tasklet_unlock_wait(&timer->tasklet);
+	kfree(timer);
+
+	return;
+}
+
+void emu10k1_timer_enable(struct emu10k1_card *card, struct emu_timer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->timer_lock, flags);
+	timer->active = 1;
+	spin_unlock_irqrestore(&card->timer_lock, flags);
+
+	return;
+}
+
+void emu10k1_timer_disable(struct emu10k1_card *card, struct emu_timer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->timer_lock, flags);
+	timer->active = 0;
+	spin_unlock_irqrestore(&card->timer_lock, flags);
+
+	return;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.h linux/drivers/sound/emu10k1/timer.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/timer.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,47 @@
+/*
+ **********************************************************************
+ *     timer.h
+ *     Copyright (C) 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+
+#ifndef _TIMER_H
+#define _TIMER_H
+
+struct emu_timer 
+{
+	struct list_head list;
+	struct tasklet_struct tasklet;
+	int active;
+	u32 count;				/* current number of interrupts */
+	u32 count_max;				/* number of interrupts needed to schedule the bh */
+	u32 delay;                              /* timer delay */
+};
+
+struct emu_timer *emu10k1_timer_install(struct emu10k1_card *, void (*)(unsigned long), unsigned long, u32);
+void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *);
+void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *);
+void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *);
+
+#define TIMER_STOPPED 0xffffffff 
+
+#endif /* _TIMER_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.c linux/drivers/sound/emu10k1/voicemgr.c
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/voicemgr.c	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,349 @@
+
+/*
+ **********************************************************************
+ *     voicemgr.c - Voice manager for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+
+struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc)
+{
+	struct emu10k1_card *card = voicemgr->card;
+	struct emu_voice *voice_tmp = voicemgr->voice;
+	struct emu_voice *voice = NULL;
+	int i;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_voice_alloc()\n");
+
+	spin_lock_irqsave(&voicemgr->lock, flags);
+
+	if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) {
+		for (i = 0; i < NUM_G; i++)
+			if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) {
+				voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
+				voice_tmp[i].usage = voiceallocdesc->usage;
+				voice = &voice_tmp[i];
+				break;
+			}
+	} else {
+		for (i = 0; i < NUM_G; i += 2)
+			if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE)
+			    && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) {
+				voice_tmp[i].linked_voice = &voice_tmp[i + 1];
+				voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
+				voice_tmp[i].usage = voiceallocdesc->usage;
+				voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags;
+				voice_tmp[i + 1].usage = voiceallocdesc->usage;
+				voice = &voice_tmp[i];
+				break;
+			}
+	}
+
+	spin_unlock_irqrestore(&voicemgr->lock, flags);
+
+	voice_tmp = voice;
+
+	while (voice_tmp != NULL) {
+
+		DPD(2, " voice allocated -> %d\n", voice_tmp->num);
+
+		sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff);
+		sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF);
+		sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff);
+		sblive_writeptr(card, PTRX, voice_tmp->num, 0);
+
+		voice_tmp = voice_tmp->linked_voice;
+	}
+
+	return voice;
+}
+
+void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice)
+{
+	struct emu10k1_card *card = voice->card;
+	struct emu_voice *voice_tmp;
+	unsigned dcysusv;
+	u32 cra, sample;
+	int i;
+	unsigned long flags;
+
+	DPF(2, "emu10k1_voice_free()\n");
+
+	voice_tmp = voice;
+
+	while (voice_tmp != NULL) {
+
+		DPD(2, " voice freed -> %d\n", voice_tmp->num);
+
+		sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK);
+		sblive_writeptr(card, IP, voice_tmp->num, 0);
+
+		dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK);
+		sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF);
+
+		sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK);
+		sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0);
+		sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK);
+		sblive_writeptr(card, CPF, voice_tmp->num, 0);
+
+		sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080;
+		cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK;
+		sblive_writeptr(card, CCR, voice_tmp->num, cra);
+		cra = (cra >> 18) & 0xf;
+		sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
+		cra = (cra + 0x1) & 0xf;
+		sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
+
+		for (i = 0; i < NUM_FXSENDS; i++)
+			voice_tmp->sendhandle[i] = 0;
+
+		voice_tmp->flags = 0;
+
+		spin_lock_irqsave(&voicemgr->lock, flags);
+		voice_tmp->usage = VOICEMGR_USAGE_FREE;
+
+		voice_tmp = voice_tmp->linked_voice;
+		voice->linked_voice = NULL;
+		spin_unlock_irqrestore(&voicemgr->lock, flags);
+	}
+
+	return;
+}
+
+/*       Sets up a voices for Wave Playback */
+
+void emu10k1_voice_playback_setup(struct emu_voice *voice)
+{
+	struct emu10k1_card *card = voice->card;
+	u32 sample, cra = 0, start = 0;
+
+	DPF(2, "emu10k1_voice_playback_setup()\n");
+
+	while (voice != NULL) {
+		sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF);
+		sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK);
+		sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK);
+		sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000);
+
+		/* Stop CA */
+		/* Assumption that PT is alreadt 0 so no harm overwriting */
+		sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b);
+
+		if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) {
+			if (voice->linked_voice != NULL) {
+				/* Set stereo bit */
+				cra = 64;
+				sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
+				sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
+			} else {
+				cra = 32;
+				sblive_writeptr(card, CPF, voice->num, 0);
+			}
+
+			if (voice->flags & VOICEMGR_FLAGS_16BIT)
+				sample = 0;
+			else {
+				cra = cra * 2;
+				sample = 0x80808080;
+			}
+			cra -= 4;
+
+			if (voice->linked_voice != NULL) {
+				/* CCR_READADDRESS_MASK */
+				sblive_writeptr(card, CCR, voice->num, 0x3c << 16);
+				sblive_writeptr(card, CCR, voice->num + 1, cra << 16);
+				sblive_writeptr(card, CDE, voice->num + 1, sample);
+				sblive_writeptr(card, CDF, voice->num + 1, sample);
+				start = voice->params.start + cra / 2;
+			} else {
+				sblive_writeptr(card, CCR, voice->num, 0x1c << 16);	/* FIXME: Is 0x1c correct? */
+				sblive_writeptr(card, CDE, voice->num, sample);
+				sblive_writeptr(card, CDF, voice->num, sample);
+				start = voice->params.start + cra;
+			}
+
+			if (start > voice->params.endloop) {
+				start -= voice->params.endloop;
+
+				if (voice->linked_voice != NULL)
+					cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9);
+				else
+					cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9);
+
+				start += voice->params.startloop;
+
+				if (start >= voice->params.endloop)
+					start = voice->params.endloop - 1;
+			} else if (voice->linked_voice != NULL)
+				cra = (cra << 25) | (0x3c << 16);
+			else
+				cra = (cra << 25) | (0x1c << 16);
+
+			start |= CCCA_INTERPROM_0;
+		}
+
+		/* CSL, ST, CA */
+		sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24));
+		sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24));
+
+		if (voice->flags & VOICEMGR_FLAGS_16BIT)
+			sblive_writeptr(card, CCCA, voice->num, start);
+		else
+			sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT);
+
+		/* Clear filter delay memory */
+		sblive_writeptr(card, Z1, voice->num, 0);
+		sblive_writeptr(card, Z2, voice->num, 0);
+
+		/* Invalidate maps */
+		sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+		sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+
+		/* Fill cache */
+		if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
+			sblive_writeptr(card, CCR, voice->num, cra);
+
+		sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
+		sblive_writeptr(card, LFOVAL1, voice->num, 0x8000);
+		sblive_writeptr(card, ATKHLDM, voice->num, 0);
+		sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK);
+		sblive_writeptr(card, LFOVAL2, voice->num, 0x8000);
+		sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch);
+		sblive_writeptr(card, PEFE, voice->num, 0x7f);
+		sblive_writeptr(card, FMMOD, voice->num, 0);
+		sblive_writeptr(card, TREMFRQ, voice->num, 0);
+		sblive_writeptr(card, FM2FRQ2, voice->num, 0);
+		sblive_writeptr(card, ENVVAL, voice->num, 0xbfff);
+		sblive_writeptr(card, ENVVOL, voice->num, 0xbfff);
+
+#ifdef PRIVATE_PCM_VOLUME
+		{
+			int i;
+
+			for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+				if (sblive_pcm_volume[i].channel_l == voice->num) {
+					voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l :
+					    // test for mono channel (reverse logic is correct here!)
+					    (sblive_pcm_volume[i].attn_r >
+					     sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r;
+					DPD(2, "set left volume  %d\n", voice->params.initial_attn);
+					break;
+				} else if (sblive_pcm_volume[i].channel_r == voice->num) {
+					voice->params.initial_attn = sblive_pcm_volume[i].attn_r;
+					DPD(2, "set right volume  %d\n", voice->params.initial_attn);
+					break;
+				}
+			}
+		}
+#endif
+		sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn);
+
+		voice->params.FC_target = 0xffff;
+		voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16);
+
+		voice = voice->linked_voice;
+	}
+
+	return;
+}
+
+void emu10k1_voice_start(struct emu_voice *voice)
+{
+	struct emu10k1_card *card = voice->card;
+
+	DPF(2, "emu10k1_voice_start()\n");
+
+	while (voice != NULL) {
+		sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target);
+
+		if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
+			sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target);
+
+		sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16)
+				| voice->params.FC_target);
+		sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16)
+				| voice->params.FC_target);
+		sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8)
+				| ENV_ON | voice->params.byampl_env_decay);
+
+		/* Using StopOnLoop for MIDI stops the playback
+		   too early, which may cause a DC level to be played
+		   until the note is released. */
+
+		if (voice->usage == VOICEMGR_USAGE_MIDI)
+			emu10k1_clear_stop_on_loop(card, voice->num);
+		else {
+			if (voice->params.startloop > voice->params.end)
+				emu10k1_set_stop_on_loop(card, voice->num);
+			else
+				emu10k1_clear_stop_on_loop(card, voice->num);
+		}
+		voice = voice->linked_voice;
+	}
+
+	return;
+}
+
+void emu10k1_voice_stop(struct emu_voice *voice)
+{
+	struct emu10k1_card *card = voice->card;
+
+	DPF(2, "emu10k1_voice_stop()\n");
+
+	while (voice != NULL) {
+		sblive_writeptr(card, IFATN, voice->num, 0xffff);
+		sblive_writeptr(card, IP, voice->num, 0);
+		sblive_writeptr(card, VTFT, voice->num, 0xffff);
+		sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0);
+		voice = voice->linked_voice;
+	}
+
+	return;
+}
+
+void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam)
+{
+	struct emu10k1_card *card = voice->card;
+	int count;
+
+	for (count = 0; count < numparam; count++)
+		sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value);
+
+	return;
+}
+
+void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value)
+{
+	struct emu10k1_card *card = voice->card;
+
+	*value = sblive_readptr(card, controlid, voice->num);
+
+	return;
+}
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.h linux/drivers/sound/emu10k1/voicemgr.h
--- v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/emu10k1/voicemgr.h	Fri Apr 21 16:08:45 2000
@@ -0,0 +1,150 @@
+/*
+ **********************************************************************
+ *     sblive_voice.h -- EMU Voice Resource Manager header file
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _VOICEMGR_H
+#define _VOICEMGR_H
+/* struct emu_voice.usage flags */
+#define VOICEMGR_USAGE_FREE         0x00000000
+#define VOICEMGR_USAGE_MIDI         0x00000001
+#define VOICEMGR_USAGE_PLAYBACK     0x00000002
+
+/* struct emu_voice.flags flags */
+#define VOICEMGR_FLAGS_MONO         0x00000002
+#define VOICEMGR_FLAGS_16BIT        0x00000004
+#define VOICEMGR_FLAGS_STEREOSLAVE  0x00000008
+#define VOICEMGR_FLAGS_VOICEMASTER  0x80000000
+#define VOICEMGR_FLAGS_FXRT2        0x00000010
+
+struct voice_param
+{
+	/* Sound engine */
+	u32 start;
+	u32 startloop;
+	u32 endloop;
+	u32 end;
+
+	u16 current_pitch;
+	u16 pitch_target;
+
+	u16 current_volume;
+	u16 volume_target;
+
+	u16 current_FC;
+	u16 FC_target;
+
+	u8 pan_target;
+	u8 aux_target;
+
+	/* FX bus amount send */
+
+	u32 send_a;
+	u32 send_b;
+	u32 send_c;
+	u32 send_d;
+
+	/* Envelope engine */
+	u16 ampl_env_delay;
+	u8 byampl_env_attack;
+	u8 byampl_env_hold;
+	u8 byampl_env_decay;
+	u8 byampl_env_sustain;
+	u8 byampl_env_release;
+
+	u16 aux_env_delay;
+	u8 byaux_env_attack;
+	u8 byaux_env_hold;
+	u8 byaux_env_decay;
+	u8 byaux_env_sustain;
+	u8 byaux_env_release;
+
+	u16 mod_LFO_delay;	/* LFO1 */
+	u16 vib_LFO_delay;	/* LFO2 */
+	u8 mod_LFO_freq;	/* LFO1 */
+	u8 vib_LFO_freq;	/* LFO2 */
+
+	s8 aux_env_to_pitch;
+	s8 aux_env_to_FC;
+	s8 mod_LFO_to_pitch;
+	s8 vib_LFO_to_pitch;
+	s8 mod_LFO_to_FC;
+	s8 mod_LFO_to_volume;
+
+	u16 sample_pitch;
+	u16 initial_pitch;
+	u8 initial_attn;
+	u8 initial_FC;
+};
+
+struct voice_allocdesc
+{
+	u32 usage;			/* playback, Midi */
+	u32 flags;			/* stereo/mono rec/playback 8/16 bit*/
+};
+
+struct emu_voice
+{
+	struct list_head list;
+
+	struct emu10k1_card *card;
+	u32 usage;		/* Free, MIDI, playback */
+	u32 num;		/* Voice ID */
+	u32 flags;		/* Stereo/mono, rec/playback, 8/16 bit */
+
+	struct voice_param params;
+
+	struct emu_voice *linked_voice;	/*for stereo voice*/
+
+	u32 sendhandle[NUM_FXSENDS];
+};
+
+struct voice_manager
+{
+	struct emu10k1_card *card;
+	spinlock_t lock;
+
+	struct emu_voice voice[NUM_G];
+};
+
+struct voice_cntlset
+{
+	u32 paramID;
+	u32 value;
+};
+
+struct emu_voice *emu10k1_voice_alloc(struct voice_manager *, struct voice_allocdesc *);
+void emu10k1_voice_free(struct voice_manager *, struct emu_voice *);
+void emu10k1_voice_playback_setup(struct emu_voice *);
+void emu10k1_voice_start(struct emu_voice *);
+void emu10k1_voice_stop(struct emu_voice *);
+void emu10k1_voice_setcontrol(struct emu_voice *, struct voice_cntlset *, u32);
+void emu10k1_voice_getcontrol(struct emu_voice *, u32, u32 *);
+
+#endif /* _VOICEMGR_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.99-pre5/linux/drivers/sound/es1370.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/sound/es1370.c	Fri Apr 21 13:26:35 2000
@@ -1268,6 +1268,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
@@ -1820,6 +1821,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int es1370_poll_dac(struct file *file, struct poll_table_struct *wait)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
@@ -2276,6 +2278,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int es1370_midi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.99-pre5/linux/drivers/sound/es1371.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/es1371.c	Fri Apr 21 13:26:09 2000
@@ -1402,6 +1402,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
@@ -1951,6 +1952,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int es1371_poll_dac(struct file *file, struct poll_table_struct *wait)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
@@ -2397,6 +2399,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int es1371_midi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.99-pre5/linux/drivers/sound/esssolo1.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/sound/esssolo1.c	Fri Apr 21 13:27:03 2000
@@ -1149,6 +1149,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
@@ -1783,6 +1784,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.3.99-pre5/linux/drivers/sound/i810_audio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/i810_audio.c	Mon Apr 24 13:39:34 2000
@@ -0,0 +1,1860 @@
+/*
+ *	Intel i810 and friends ICH driver for Linux
+ *	Alan Cox <alan@redhat.com>
+ *
+ *  Built from:
+ *	Low level code:  Zach Brown (original nonworking i810 OSS driver)
+ *			 Jaroslav Kysela <perex@suse.cz> (working ALSA driver)
+ *
+ *	Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *	Extended by: Zach Brown <zab@redhat.com>  
+ *			and others..
+ *
+ *  Hardware Provided By:
+ *	Analog Devices (A major AC97 codec maker)
+ *	Intel Corp  (you've probably heard of them already)
+ *
+ *	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.
+ *
+ *
+ *	Intel 810 theory of operation
+ *
+ *	The chipset provides three DMA channels that talk to an AC97
+ *	CODEC (AC97 is a digital/analog mixer standard). At its simplest
+ *	you get 48Khz audio with basic volume and mixer controls. At the
+ *	best you get rate adaption in the codec. We set the card up so
+ *	that we never take completion interrupts but instead keep the card
+ *	chasing its tail around a ring buffer. This is needed for mmap
+ *	mode audio and happens to work rather well for non-mmap modes too.
+ *
+ *	The board has one output channel for PCM audio (supported) and
+ *	a stereo line in and mono microphone input. Again these are normally
+ *	locked to 48Khz only. Right now recording is not finished.
+ *
+ *	There is no midi support, no synth support. Use timidity. To get
+ *	esd working you need to use esd -r 48000 as it won't probe 48KHz
+ *	by default. mpg123 can't handle 48Khz only audio so use xmms.
+ */
+ 
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/ac97_codec.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+
+#ifndef PCI_DEVICE_ID_INTEL_82801
+#define PCI_DEVICE_ID_INTEL_82801	0x2415
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82901
+#define PCI_DEVICE_ID_INTEL_82901	0x2425
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_440MX
+#define PCI_DEVICE_ID_INTEL_440MX	0x7195
+#endif
+
+#define ADC_RUNNING	1
+#define DAC_RUNNING	2
+
+#define I810_FMT_16BIT	1
+#define I810_FMT_STEREO	2
+#define I810_FMT_MASK	3
+
+/* the 810's array of pointers to data buffers */
+
+struct sg_item {
+#define BUSADDR_MASK	0xFFFFFFFE
+	u32 busaddr;	
+#define CON_IOC 	0x80000000 /* interrupt on completion */
+#define CON_BUFPAD	0x40000000 /* pad underrun with last sample, else 0 */
+#define CON_BUFLEN_MASK	0x0000ffff /* buffer length in samples */
+	u32 control;
+};
+
+/* an instance of the i810 channel */
+#define SG_LEN 32
+struct i810_channel 
+{
+	/* these sg guys should probably be allocated
+	   seperately as nocache. Must be 8 byte aligned */
+	struct sg_item sg[SG_LEN];	/* 32*8 */
+	u32 offset;			/* 4 */
+	u32 port;			/* 4 */
+	u32 used;
+	u32 num;
+};
+
+/*
+ * we have 3 seperate dma engines.  pcm in, pcm out, and mic.
+ * each dma engine has controlling registers.  These goofy
+ * names are from the datasheet, but make it easy to write
+ * code while leafing through it.
+ */
+
+#define ENUM_ENGINE(PRE,DIG) 									\
+enum {												\
+	##PRE##_BDBAR =	0x##DIG##0,		/* Buffer Descriptor list Base Address */	\
+	##PRE##_CIV =	0x##DIG##4,		/* Current Index Value */			\
+	##PRE##_LVI =	0x##DIG##5,		/* Last Valid Index */				\
+	##PRE##_SR =	0x##DIG##6,		/* Status Register */				\
+	##PRE##_PICB =	0x##DIG##8,		/* Position In Current Buffer */		\
+	##PRE##_PIV =	0x##DIG##a,		/* Prefetched Index Value */			\
+	##PRE##_CR =	0x##DIG##b		/* Control Register */				\
+}
+
+ENUM_ENGINE(OFF,0);	/* Offsets */
+ENUM_ENGINE(PI,0);	/* PCM In */
+ENUM_ENGINE(PO,1);	/* PCM Out */
+ENUM_ENGINE(MC,2);	/* Mic In */
+
+enum {
+	GLOB_CNT =	0x2c,			/* Global Control */
+	GLOB_STA = 	0x30,			/* Global Status */
+	CAS	 = 	0x34			/* Codec Write Semaphore Register */
+};
+
+/* interrupts for a dma engine */
+#define DMA_INT_FIFO		(1<<4)  /* fifo under/over flow */
+#define DMA_INT_COMPLETE	(1<<3)  /* buffer read/write complete and ioc set */
+#define DMA_INT_LVI		(1<<2)  /* last valid done */
+#define DMA_INT_CELV		(1<<1)  /* last valid is current */
+#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
+
+/* interrupts for the whole chip */
+#define INT_SEC		(1<<11)
+#define INT_PRI		(1<<10)
+#define INT_MC		(1<<7)
+#define INT_PO		(1<<6)
+#define INT_PI		(1<<5)
+#define INT_MO		(1<<2)
+#define INT_NI		(1<<1)
+#define INT_GPI		(1<<0)
+#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
+
+
+#define DRIVER_VERSION "0.01"
+
+/* magic numbers to protect our data structures */
+#define I810_CARD_MAGIC		0x5072696E /* "Prin" */
+#define I810_STATE_MAGIC	0x63657373 /* "cess" */
+#define I810_DMA_MASK		0xffffffff /* DMA buffer mask for pci_alloc_consist */
+#define NR_HW_CH		3
+
+/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+#define NR_AC97		2
+
+/* minor number of /dev/dspW */
+#define SND_DEV_DSP8	1
+
+/* minor number of /dev/dspW */
+#define SND_DEV_DSP16	1 
+
+static const unsigned sample_size[] = { 1, 2, 2, 4 };
+static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+
+enum {
+	ICH82801AA = 0,
+	ICH82901AB,
+	INTEL440MX
+};
+
+static char * card_names[] = {
+	"Intel ICH 82801AA",
+	"Intel ICH 82901AB",
+	"Intel 440MX"
+};
+
+static struct pci_device_id i810_pci_tbl [] __initdata = {
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82901,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE (pci, i810_pci_tbl);
+
+/* "software" or virtual channel, an instance of opened /dev/dsp */
+struct i810_state {
+	unsigned int magic;
+	struct i810_card *card;	/* Card info */
+
+	/* single open lock mechanism, only used for recording */
+	struct semaphore open_sem;
+	wait_queue_head_t open_wait;
+
+	/* file mode */
+	mode_t open_mode;
+
+	/* virtual channel number */
+	int virt;
+
+	struct dmabuf {
+		/* wave sample stuff */
+		unsigned int rate;
+		unsigned char fmt, enable;
+
+		/* hardware channel */
+		struct i810_channel *channel;
+
+		/* OSS buffer management stuff */
+		void *rawbuf;
+		dma_addr_t dma_handle;
+		unsigned buforder;
+		unsigned numfrag;
+		unsigned fragshift;
+
+		/* our buffer acts like a circular ring */
+		unsigned hwptr;		/* where dma last started, updated by update_ptr */
+		unsigned swptr;		/* where driver last clear/filled, updated by read/write */
+		int count;		/* bytes to be comsumed or been generated by dma machine */
+		unsigned total_bytes;	/* total bytes dmaed by hardware */
+
+		unsigned error;		/* number of over/underruns */
+		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
+
+		/* redundant, but makes calculations easier */
+		unsigned fragsize;
+		unsigned dmasize;
+		unsigned fragsamples;
+
+		/* OSS stuff */
+		unsigned mapped:1;
+		unsigned ready:1;
+		unsigned endcleared:1;
+		unsigned update_flag;
+		unsigned ossfragshift;
+		int ossmaxfrags;
+		unsigned subdivision;
+	} dmabuf;
+};
+
+
+struct i810_card {
+	struct i810_channel channel[3];
+	unsigned int magic;
+
+	/* We keep i810 cards in a linked list */
+	struct i810_card *next;
+
+	/* The i810 has a certain amount of cross channel interaction
+	   so we use a single per card lock */
+	spinlock_t lock;
+
+	/* PCI device stuff */
+	struct pci_dev * pci_dev;
+	u16 pci_id;
+
+	/* soundcore stuff */
+	int dev_audio;
+
+	/* structures for abstraction of hardware facilities, codecs, banks and channels*/
+	struct ac97_codec *ac97_codec[NR_AC97];
+	struct i810_state *states[NR_HW_CH];
+
+	u16 ac97_features;
+	
+	/* hardware resources */
+	unsigned long iobase;
+	unsigned long ac97base;
+	u32 irq;
+	
+	/* Function support */
+	struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
+	struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
+	void (*free_pcm_channel)(struct i810_card *, int chan);
+};
+
+static struct i810_card *devs = NULL;
+
+static int i810_open_mixdev(struct inode *inode, struct file *file);
+static int i810_release_mixdev(struct inode *inode, struct file *file);
+static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+				unsigned long arg);
+static loff_t i810_llseek(struct file *file, loff_t offset, int origin);
+
+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;
+}
+
+static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+
+static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
+{
+	if(card->channel[1].used==1)
+		return NULL;
+	card->channel[1].used=1;
+	card->channel[1].offset = 0;
+	card->channel[1].port = 0x10;
+	card->channel[1].num=1;
+	return &card->channel[1];
+}
+
+static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card)
+{
+	if(card->channel[0].used==1)
+		return NULL;
+	card->channel[0].used=1;
+	card->channel[0].offset = 0;
+	card->channel[0].port = 0x00;
+	card->channel[1].num=0;
+	return &card->channel[0];
+}
+
+static void i810_free_pcm_channel(struct i810_card *card, int channel)
+{
+	card->channel[channel].used=0;
+}
+
+/* set playback sample rate */
+static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
+{	
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u16 dacp, rp;
+	struct ac97_codec *codec=state->card->ac97_codec[0];
+	
+	if(!(state->card->ac97_features&0x0001))
+		return 48000;
+			
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 4000)
+		rate = 4000;
+
+	/* Power down the DAC */
+	dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+	i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
+	
+	/* Load the rate and read the effective rate */
+	i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
+	rp=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
+	
+	printk("DAC rate set to %d Returned %d\n", 
+		rate, (int)rp);
+		
+	rate=rp;
+		
+	/* Power it back up */
+	i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+	
+	dmabuf->rate = rate;
+#ifdef DEBUG
+	printk("i810_audio: called i810_set_dac_rate : rate = %d\n", rate);
+#endif
+
+	return rate;
+}
+
+/* set recording sample rate */
+static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u16 dacp, rp;
+	struct ac97_codec *codec=state->card->ac97_codec[0];
+	
+	if(!(state->card->ac97_features&0x0001))
+		return 48000;
+			
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 4000)
+		rate = 4000;
+
+	/* Power down the ADC */
+	dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+	i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
+	
+	/* Load the rate and read the effective rate */
+	i810_ac97_set(codec, AC97_PCM_LR_ADC_RATE, rate);
+	rp=i810_ac97_get(codec, AC97_PCM_LR_ADC_RATE);
+	
+	printk("ADC rate set to %d Returned %d\n", 
+		rate, (int)rp);
+		
+	rate=rp;
+		
+	/* Power it back up */
+	i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+	
+	dmabuf->rate = rate;
+#ifdef DEBUG
+	printk("i810_audio: called i810_set_adc_rate : rate = %d\n", rate);
+#endif
+
+	return rate;
+
+}
+
+/* prepare channel attributes for playback */ 
+static void i810_play_setup(struct i810_state *state)
+{
+//	struct dmabuf *dmabuf = &state->dmabuf;
+//	struct i810_channel *channel = dmabuf->channel;
+	/* Fixed format. .. */
+	//if (dmabuf->fmt & I810_FMT_16BIT)
+	//if (dmabuf->fmt & I810_FMT_STEREO)
+}
+
+/* prepare channel attributes for recording */
+static void i810_rec_setup(struct i810_state *state)
+{
+//	u16 w;
+//	struct i810_card *card = state->card;
+//	struct dmabuf *dmabuf = &state->dmabuf;
+//	struct i810_channel *channel = dmabuf->channel;
+
+	/* Enable AC-97 ADC (capture) */
+//	if (dmabuf->fmt & I810_FMT_16BIT) {
+//	if (dmabuf->fmt & I810_FMT_STEREO)
+}
+
+
+/* get current playback/recording dma buffer pointer (byte offset from LBA),
+   called with spinlock held! */
+   
+extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 offset;
+	struct i810_channel *c = dmabuf->channel;
+	
+	if (!dmabuf->enable)
+		return 0;
+	offset = inb(state->card->iobase+c->port+OFF_CIV);
+	offset++;
+	offset&=31;
+	/* Offset has to compensate for the fact we finished the segment
+	   on the IRQ so we are at next_segment,0 */
+//	printk("BANK%d ", offset);
+	offset *= (dmabuf->dmasize/SG_LEN);
+//	printk("DMASZ=%d", dmabuf->dmasize);
+//	offset += 1024-(4*inw(state->card->iobase+c->port+OFF_PICB));
+//	printk("OFF%d ", offset);
+	return offset;
+}
+
+static void resync_dma_ptrs(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct i810_channel *c = dmabuf->channel;
+	int offset;
+	
+	offset = inb(state->card->iobase+c->port+OFF_CIV);
+	offset *= (dmabuf->dmasize/SG_LEN);
+	
+	dmabuf->hwptr=dmabuf->swptr = offset;
+}
+	
+/* Stop recording (lock held) */
+extern __inline__ void __stop_adc(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct i810_card *card = state->card;
+
+	dmabuf->enable &= ~ADC_RUNNING;
+	outb(0, card->iobase + PI_CR);
+}
+
+static void stop_adc(struct i810_state *state)
+{
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void start_adc(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) {
+		dmabuf->enable |= ADC_RUNNING;
+		outb((1<<4) | 1<<2 | 1, card->iobase + PI_CR);
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* stop playback (lock held) */
+extern __inline__ void __stop_dac(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct i810_card *card = state->card;
+
+	dmabuf->enable &= ~DAC_RUNNING;
+	outb(0, card->iobase + PO_CR);
+}
+
+static void stop_dac(struct i810_state *state)
+{
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}	
+
+static void start_dac(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
+		if(!(dmabuf->enable&DAC_RUNNING))
+		{
+			dmabuf->enable |= DAC_RUNNING;
+			outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR);
+		}
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
+#define DMABUF_MINORDER 1
+
+/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
+static int alloc_dmabuf(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	void *rawbuf;
+	int order;
+	unsigned long map, mapend;
+
+	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
+	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
+						   PAGE_SIZE << order,
+						   &dmabuf->dma_handle)))
+			break;
+	if (!rawbuf)
+		return -ENOMEM;
+
+#ifdef DEBUG
+	printk("i810_audio: allocated %ld (order = %d) bytes at %p\n",
+	       PAGE_SIZE << order, order, rawbuf);
+#endif
+
+	dmabuf->ready  = dmabuf->mapped = 0;
+	dmabuf->rawbuf = rawbuf;
+	dmabuf->buforder = order;
+	
+	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+	mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+	for (map = MAP_NR(rawbuf); map <= mapend; map++)
+		set_bit(PG_reserved, &mem_map[map].flags);
+
+	return 0;
+}
+
+/* free DMA buffer */
+static void dealloc_dmabuf(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long map, mapend;
+
+	if (dmabuf->rawbuf) {
+		/* undo marking the pages as reserved */
+		mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+		for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++)
+			clear_bit(PG_reserved, &mem_map[map].flags);
+		pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
+				    dmabuf->rawbuf, dmabuf->dma_handle);
+	}
+	dmabuf->rawbuf = NULL;
+	dmabuf->mapped = dmabuf->ready = 0;
+}
+
+static int prog_dmabuf(struct i810_state *state, unsigned rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct sg_item *sg;
+	unsigned bytepersec;
+	unsigned bufsize;
+	unsigned long flags;
+	int ret;
+	unsigned fragsize;
+	int i;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	resync_dma_ptrs(state);
+	dmabuf->total_bytes = 0;
+	dmabuf->count = dmabuf->error = 0;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* allocate DMA buffer if not allocated yet */
+	if (!dmabuf->rawbuf)
+		if ((ret = alloc_dmabuf(state)))
+			return ret;
+
+	/* FIXME: figure out all this OSS fragment stuff */
+	bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt];
+	bufsize = PAGE_SIZE << dmabuf->buforder;
+	if (dmabuf->ossfragshift) {
+		if ((1000 << dmabuf->ossfragshift) < bytepersec)
+			dmabuf->fragshift = ld2(bytepersec/1000);
+		else
+			dmabuf->fragshift = dmabuf->ossfragshift;
+	} else {
+		/* lets hand out reasonable big ass buffers by default */
+		dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
+	}
+	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+	while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
+		dmabuf->fragshift--;
+		dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+	}
+	dmabuf->fragsize = 1 << dmabuf->fragshift;
+	if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag)
+		dmabuf->numfrag = dmabuf->ossmaxfrags;
+	dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];
+	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
+
+	memset(dmabuf->rawbuf, (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80,
+	       dmabuf->dmasize);
+
+	/*
+	 *	Now set up the ring 
+	 */
+
+	sg=&dmabuf->channel->sg[0];
+	fragsize = bufsize / SG_LEN;
+	
+	/*
+	 *	Load up 32 sg entries and take an interrupt at half
+	 *	way (we might want more interrupts later..) 
+	 */
+	  
+	for(i=0;i<32;i++)
+	{
+		sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i);
+		sg->control=(fragsize>>1);
+		sg->control|=CON_IOC;
+		sg++;
+	}
+	spin_lock_irqsave(&state->card->lock, flags);
+	outl(virt_to_bus(&dmabuf->channel->sg[0]), state->card->iobase+dmabuf->channel->port+OFF_BDBAR);
+	outb(16, state->card->iobase+dmabuf->channel->port+OFF_LVI);
+	outb(0, state->card->iobase+dmabuf->channel->port+OFF_CIV);
+	if (rec) {
+		i810_rec_setup(state);
+	} else {
+		i810_play_setup(state);
+	}
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* set the ready flag for the dma buffer */
+	dmabuf->ready = 1;
+
+#ifdef DEBUG
+	printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, "
+	       "fragsize = %d dmasize = %d\n",
+	       dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
+	       dmabuf->fragsize, dmabuf->dmasize);
+#endif
+
+	return 0;
+}
+
+/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e.
+   |------------|------------|   or   |xxxxxxxxxxxx|------------|   or   |xxxxxxxxxxxx|xxxxxxxxxxxx|
+   but we almost always get this
+   |xxxxxx------|------------|   or   |xxxxxxxxxxxx|xxxxx-------|
+   so we have to clear the tail space to "silence"
+   |xxxxxx000000|------------|   or   |xxxxxxxxxxxx|xxxxxx000000|
+*/
+static void i810_clear_tail(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned swptr;
+	unsigned char silence = (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80;
+	unsigned int len;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	swptr = dmabuf->swptr;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize)
+		return;
+
+	if (swptr < dmabuf->dmasize/2)
+		len = dmabuf->dmasize/2 - swptr;
+	else
+		len = dmabuf->dmasize - swptr;
+
+	memset(dmabuf->rawbuf + swptr, silence, len);
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	dmabuf->swptr += len;
+	dmabuf->count += len;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* restart the dma machine in case it is halted */
+	start_dac(state);
+}
+
+static int drain_dac(struct i810_state *state, int nonblock)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned long tmo;
+	int count;
+
+	if (dmabuf->mapped || !dmabuf->ready)
+		return 0;
+
+	add_wait_queue(&dmabuf->wait, &wait);
+	for (;;) {
+		/* It seems that we have to set the current state to TASK_INTERRUPTIBLE
+		   every time to make the process really go to sleep */
+		current->state = TASK_INTERRUPTIBLE;
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		count = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (count <= 0)
+			break;
+
+		if (signal_pending(current))
+			break;
+
+		if (nonblock) {
+			remove_wait_queue(&dmabuf->wait, &wait);
+			current->state = TASK_RUNNING;
+			return -EBUSY;
+		}
+
+		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
+		tmo >>= sample_shift[dmabuf->fmt];
+		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
+			printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
+			break;
+		}
+	}
+	remove_wait_queue(&dmabuf->wait, &wait);
+	current->state = TASK_RUNNING;
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	return 0;
+}
+
+/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
+static void i810_update_ptr(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned hwptr, swptr;
+	int clear_cnt = 0;
+	int diff;
+	unsigned char silence;
+//	unsigned half_dmasize;
+
+	/* update hardware pointer */
+	hwptr = i810_get_dma_addr(state);
+	diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+//	printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+	dmabuf->hwptr = hwptr;
+	dmabuf->total_bytes += diff;
+
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == ADC_RUNNING) {
+		if (dmabuf->mapped) {
+			dmabuf->count -= diff;
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			dmabuf->count += diff;
+
+			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+				/* buffer underrun or buffer overrun, we have no way to recover
+				   it here, just stop the machine and let the process force hwptr
+				   and swptr to sync */
+				__stop_adc(state);
+				dmabuf->error++;
+			}
+			else if (!dmabuf->endcleared) {
+				swptr = dmabuf->swptr;
+				silence = (dmabuf->fmt & I810_FMT_16BIT ? 0 : 0x80);
+				if (dmabuf->count < (signed) dmabuf->fragsize) 
+				{
+					clear_cnt = dmabuf->fragsize;
+					if ((swptr + clear_cnt) > dmabuf->dmasize)
+						clear_cnt = dmabuf->dmasize - swptr;
+					memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
+					dmabuf->endcleared = 1;
+				}
+			}			
+			wake_up(&dmabuf->wait);
+		}
+	}
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == DAC_RUNNING) {
+		if (dmabuf->mapped) {
+			dmabuf->count += diff;
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			dmabuf->count -= diff;
+
+			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+				/* buffer underrun or buffer overrun, we have no way to recover
+				   it here, just stop the machine and let the process force hwptr
+				   and swptr to sync */
+				__stop_dac(state);
+				printk("DMA overrun on send\n");
+				dmabuf->error++;
+			}
+			wake_up(&dmabuf->wait);
+		}
+	}
+}
+
+static void i810_channel_interrupt(struct i810_card *card)
+{
+	int i;
+
+//	printk("CHANNEL IRQ .. ");	
+	for(i=0;i<NR_HW_CH;i++)
+	{
+		struct i810_state *state = card->states[i];
+		struct i810_channel *c;
+		unsigned long port = card->iobase;
+		u16 status;
+		
+		if(!state)
+			continue;
+		if(!state->dmabuf.ready)
+			continue;
+		c=state->dmabuf.channel;
+		
+		port+=c->port;
+		
+//		printk("PORT %lX (", port);
+		
+		status = inw(port + OFF_SR);
+		
+//		printk("ST%d ", status);
+		
+		if(status & DMA_INT_LVI)
+		{
+			/* Back to the start */
+//			printk("LVI - STOP");
+			outb((inb(port+OFF_CIV)-1)&31, port+OFF_LVI);
+			i810_update_ptr(state);
+			outb(0, port + OFF_CR);
+		}
+		if(status & DMA_INT_COMPLETE)
+		{
+			int x;
+			/* Keep the card chasing its tail */
+			outb(x=((inb(port+OFF_CIV)-1)&31), port+OFF_LVI);
+			i810_update_ptr(state);
+//			printk("COMP%d ",x);
+		}
+//		printk(")");
+		outw(status & DMA_INT_MASK, port + OFF_SR);
+	}
+//	printk("\n");
+}
+
+static void i810_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct i810_card *card = (struct i810_card *)dev_id;
+	u32 status;
+
+	spin_lock(&card->lock);
+
+	status = inl(card->iobase + GLOB_STA);
+	if(!(status & INT_MASK)) 
+		return;  /* not for us */
+
+//	printk("Interrupt %X: ", status);
+	if(status & (INT_PO|INT_PI|INT_MC))
+		i810_channel_interrupt(card);
+
+ 	/* clear 'em */
+	outl(status & INT_MASK, card->iobase + GLOB_STA);
+	spin_unlock(&card->lock);
+}
+
+static loff_t i810_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
+   the user's buffer.  it is filled by the dma machine and drained by this loop. */
+static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+
+#ifdef DEBUG
+	printk("i810_audio: i810_read called, count = %d\n", count);
+#endif
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+		return ret;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	ret = 0;
+
+	while (count > 0) {
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (dmabuf->count > (signed) dmabuf->dmasize) {
+			/* buffer overrun, we are recovering from sleep_on_timeout,
+			   resync hwptr and swptr, make process flush the buffer */
+			dmabuf->count = dmabuf->dmasize;
+			dmabuf->swptr = dmabuf->hwptr;
+		}
+		swptr = dmabuf->swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if (dmabuf->count < cnt)
+			cnt = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			/* buffer is empty, start the dma machine and wait for data to be
+			   recorded */
+			start_adc(state);
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret) ret = -EAGAIN;
+				return ret;
+			}
+			/* This isnt strictly right for the 810  but it'll do */
+			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+			tmo >>= sample_shift[dmabuf->fmt];
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer overrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+				printk(KERN_ERR "i810_audio: recording schedule timeout, "
+				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				       dmabuf->hwptr, dmabuf->swptr);
+#endif
+				/* a buffer overrun, we delay the recovery untill next time the
+				   while loop begin and we REALLY have space to record */
+			}
+			if (signal_pending(current)) {
+				ret = ret ? ret : -ERESTARTSYS;
+				return ret;
+			}
+			continue;
+		}
+
+		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
+			if (!ret) ret = -EFAULT;
+			return ret;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		dmabuf->swptr = swptr;
+		dmabuf->count -= cnt;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_adc(state);
+	}
+	return ret;
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
+   the soundcard.  it is drained by the dma machine and filled by this loop. */
+static ssize_t i810_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+
+#ifdef DEBUG
+	printk("i810_audio: i810_write called, count = %d\n", count);
+#endif
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+		return ret;
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+	ret = 0;
+
+	while (count > 0) {
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (dmabuf->count < 0) {
+			/* buffer underrun, we are recovering from sleep_on_timeout,
+			   resync hwptr and swptr */
+			dmabuf->count = 0;
+			dmabuf->swptr = dmabuf->hwptr;
+		}
+		swptr = dmabuf->swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if (dmabuf->count + cnt > dmabuf->dmasize)
+			cnt = dmabuf->dmasize - dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			/* buffer is full, start the dma machine and wait for data to be
+			   played */
+			start_dac(state);
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret) ret = -EAGAIN;
+				return ret;
+			}
+			/* Not strictly correct but works */
+			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+			tmo >>= sample_shift[dmabuf->fmt];
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer underrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+				printk(KERN_ERR "i810_audio: playback schedule timeout, "
+				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				       dmabuf->hwptr, dmabuf->swptr);
+#endif
+				/* a buffer underrun, we delay the recovery untill next time the
+				   while loop begin and we REALLY have data to play */
+			}
+			if (signal_pending(current)) {
+				if (!ret) ret = -ERESTARTSYS;
+				return ret;
+			}
+			continue;
+		}
+		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+			if (!ret) ret = -EFAULT;
+			return ret;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		dmabuf->swptr = swptr;
+		dmabuf->count += cnt;
+		dmabuf->endcleared = 0;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_dac(state);
+	}
+	return ret;
+}
+
+/* No kernel lock - we have our own spinlock */
+static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	if (file->f_mode & FMODE_WRITE)
+		poll_wait(file, &dmabuf->wait, wait);
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &dmabuf->wait, wait);
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	i810_update_ptr(state);
+	if (file->f_mode & FMODE_READ) {
+		if (dmabuf->count >= (signed)dmabuf->fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (dmabuf->mapped) {
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	return mask;
+}
+
+static int i810_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int ret;
+	unsigned long size;
+
+	if (vma->vm_flags & VM_WRITE) {
+		if ((ret = prog_dmabuf(state, 0)) != 0)
+			return ret;
+	} else if (vma->vm_flags & VM_READ) {
+		if ((ret = prog_dmabuf(state, 1)) != 0)
+			return ret;
+	} else 
+		return -EINVAL;
+
+	if (vma->vm_pgoff != 0)
+		return -EINVAL;
+	size = vma->vm_end - vma->vm_start;
+	if (size > (PAGE_SIZE << dmabuf->buforder))
+		return -EINVAL;
+	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+			     size, vma->vm_page_prot))
+		return -EAGAIN;
+	dmabuf->mapped = 1;
+
+	return 0;
+}
+
+static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	audio_buf_info abinfo;
+	count_info cinfo;
+	int val, mapped, ret;
+
+	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
+		((file->f_mode & FMODE_READ) && dmabuf->mapped);
+#ifdef DEBUG
+	printk("i810_audio: i810_ioctl, command = %2d, arg = 0x%08x\n",
+	       _IOC_NR(cmd), arg ? *(int *)arg : 0);
+#endif
+
+	switch (cmd) 
+	{
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		/* FIXME: spin_lock ? */
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(state);
+			synchronize_irq();
+			dmabuf->ready = 0;
+			resync_dma_ptrs(state);
+			dmabuf->swptr = dmabuf->hwptr = 0;
+			dmabuf->count = dmabuf->total_bytes = 0;
+		}
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(state);
+			synchronize_irq();
+			resync_dma_ptrs(state);
+			dmabuf->ready = 0;
+			dmabuf->swptr = dmabuf->hwptr = 0;
+			dmabuf->count = dmabuf->total_bytes = 0;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SYNC:
+		if (file->f_mode & FMODE_WRITE)
+			return drain_dac(state, file->f_flags & O_NONBLOCK);
+		return 0;
+
+	case SNDCTL_DSP_SPEED: /* set smaple rate */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val >= 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				dmabuf->ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				i810_set_dac_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				i810_set_adc_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+		}
+		return put_user(dmabuf->rate, (int *)arg);
+
+	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if(val==0)
+			return -EINVAL;
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(state);
+			dmabuf->ready = 0;
+			dmabuf->fmt = I810_FMT_STEREO;
+		}
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(state);
+			dmabuf->ready = 0;
+			dmabuf->fmt = I810_FMT_STEREO;
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE) {
+			if ((val = prog_dmabuf(state, 0)))
+				return val;
+			return put_user(dmabuf->fragsize, (int *)arg);
+		}
+		if (file->f_mode & FMODE_READ) {
+			if ((val = prog_dmabuf(state, 1)))
+				return val;
+			return put_user(dmabuf->fragsize, (int *)arg);
+		}
+
+	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+		return put_user(AFMT_S16_LE, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT: /* Select sample format */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != AFMT_QUERY) {
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				dmabuf->ready = 0;
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+			}
+		}
+		return put_user(AFMT_S16_LE, (int *)arg);
+
+	case SNDCTL_DSP_CHANNELS:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				dmabuf->ready = 0;
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+			}
+		}
+		return put_user(2, (int *)arg);
+
+	case SNDCTL_DSP_POST:
+		/* FIXME: the same as RESET ?? */
+		return 0;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		if (dmabuf->subdivision)
+			return -EINVAL;
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+		dmabuf->subdivision = val;
+		return 0;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		get_user_ret(val, (int *)arg, -EFAULT);
+
+		dmabuf->ossfragshift = val & 0xffff;
+		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+		if (dmabuf->ossfragshift < 4)
+			dmabuf->ossfragshift = 4;
+		if (dmabuf->ossfragshift > 15)
+			dmabuf->ossfragshift = 15;
+		if (dmabuf->ossmaxfrags < 4)
+			dmabuf->ossmaxfrags = 4;
+
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		i810_update_ptr(state);
+		abinfo.fragsize = dmabuf->fragsize;
+		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		abinfo.fragstotal = dmabuf->numfrag;
+		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+		spin_unlock_irqrestore(&state->card->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 (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		i810_update_ptr(state);
+		abinfo.fragsize = dmabuf->fragsize;
+		abinfo.bytes = dmabuf->count;
+		abinfo.fragstotal = dmabuf->numfrag;
+		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+		spin_unlock_irqrestore(&state->card->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_GETCAPS:
+	    return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
+			    (int *)arg);
+
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		if (file->f_mode & FMODE_READ && dmabuf->enable)
+			val |= PCM_ENABLE_INPUT;
+		if (file->f_mode & FMODE_WRITE && dmabuf->enable)
+			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 (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+					return ret;
+				start_adc(state);
+			} else
+				stop_adc(state);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT) {
+				if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+					return ret;
+				start_dac(state);
+			} else
+				stop_dac(state);
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		i810_update_ptr(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped)
+			dmabuf->count &= dmabuf->fragsize-1;
+		spin_unlock_irqrestore(&state->card->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(&state->card->lock, flags);
+		i810_update_ptr(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped)
+			dmabuf->count &= dmabuf->fragsize-1;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+	case SNDCTL_DSP_SETDUPLEX:
+		return -EINVAL;
+
+	case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		i810_update_ptr(state);
+		val = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return put_user(val, (int *)arg);
+
+	case SOUND_PCM_READ_RATE:
+		return put_user(dmabuf->rate, (int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+		return put_user((dmabuf->fmt & I810_FMT_STEREO) ? 2 : 1,
+				(int *)arg);
+
+	case SOUND_PCM_READ_BITS:
+		return put_user(AFMT_S16_LE, (int *)arg);
+
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
+	case SOUND_PCM_READ_FILTER:
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static int i810_open(struct inode *inode, struct file *file)
+{
+	int i = 0;
+	int minor = MINOR(inode->i_rdev);
+	struct i810_card *card = devs;
+	struct i810_state *state = NULL;
+	struct dmabuf *dmabuf = NULL;
+
+	/* find an avaiable virtual channel (instance of /dev/dsp) */
+	while (card != NULL) {
+		for (i = 0; i < NR_HW_CH; i++) {
+			if (card->states[i] == NULL) {
+				state = card->states[i] = (struct i810_state *)
+					kmalloc(sizeof(struct i810_state), GFP_KERNEL);
+				if (state == NULL)
+					return -ENOMEM;
+				memset(state, 0, sizeof(struct i810_state));
+				dmabuf = &state->dmabuf;
+				goto found_virt;
+			}
+		}
+		card = card->next;
+	}
+	/* no more virtual channel avaiable */
+	if (!state)
+		return -ENODEV;
+
+ found_virt:
+	/* found a free virtual channel, allocate hardware channels */
+	if(file->f_mode & FMODE_READ)
+		dmabuf->channel = card->alloc_rec_pcm_channel(card);
+	else
+		dmabuf->channel = card->alloc_pcm_channel(card);
+		
+	if (dmabuf->channel == NULL) {
+		kfree (card->states[i]);
+		card->states[i] = NULL;;
+		return -ENODEV;
+	}
+
+	/* initialize the virtual channel */
+	state->virt = i;
+	state->card = card;
+	state->magic = I810_STATE_MAGIC;
+	init_waitqueue_head(&dmabuf->wait);
+	init_MUTEX(&state->open_sem);
+	file->private_data = state;
+
+	down(&state->open_sem);
+
+	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
+	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
+	   /dev/dspW will accept 16-bits sample */
+	if (file->f_mode & FMODE_WRITE) {
+		dmabuf->fmt &= ~I810_FMT_MASK;
+		dmabuf->fmt |= I810_FMT_16BIT;
+		dmabuf->ossfragshift = 0;
+		dmabuf->ossmaxfrags  = 0;
+		dmabuf->subdivision  = 0;
+		i810_set_dac_rate(state, 48000);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		dmabuf->fmt &= ~I810_FMT_MASK;
+		dmabuf->fmt |= I810_FMT_16BIT;
+		dmabuf->ossfragshift = 0;
+		dmabuf->ossmaxfrags  = 0;
+		dmabuf->subdivision  = 0;
+		i810_set_adc_rate(state, 48000);
+	}
+
+	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	up(&state->open_sem);
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int i810_release(struct inode *inode, struct file *file)
+{
+	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	if (file->f_mode & FMODE_WRITE) {
+		i810_clear_tail(state);
+		drain_dac(state, file->f_flags & O_NONBLOCK);
+	}
+
+	/* stop DMA state machine and free DMA buffers/channels */
+	down(&state->open_sem);
+
+	if (file->f_mode & FMODE_WRITE) {
+		stop_dac(state);
+		dealloc_dmabuf(state);
+		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
+	}
+	if (file->f_mode & FMODE_READ) {
+		stop_adc(state);
+		dealloc_dmabuf(state);
+		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
+	}
+
+	kfree(state->card->states[state->virt]);
+	state->card->states[state->virt] = NULL;
+	state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+
+	/* we're covered by the open_sem */
+	up(&state->open_sem);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static /*const*/ struct file_operations i810_audio_fops = {
+	llseek:		i810_llseek,
+	read:		i810_read,
+	write:		i810_write,
+	poll:		i810_poll,
+	ioctl:		i810_ioctl,
+	mmap:		i810_mmap,
+	open:		i810_open,
+	release:	i810_release,
+};
+
+/* Write AC97 codec registers */
+
+static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+
+	while(count-- && (inb(card->iobase + CAS) & 1)) 
+		udelay(1);
+	return inw(card->ac97base + (reg&0x7f));
+}
+
+static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+
+	while(count-- && (inb(card->iobase + CAS) & 1)) 
+		udelay(1);
+	outw(data, card->ac97base + (reg&0x7f));
+}
+
+
+/* OSS /dev/mixer file operation methods */
+
+static int i810_open_mixdev(struct inode *inode, struct file *file)
+{
+	int i;
+	int minor = MINOR(inode->i_rdev);
+	struct i810_card *card = devs;
+
+	for (card = devs; card != NULL; card = card->next)
+		for (i = 0; i < NR_AC97; i++)
+			if (card->ac97_codec[i] != NULL &&
+			    card->ac97_codec[i]->dev_mixer == minor)
+				goto match;
+
+	if (!card)
+		return -ENODEV;
+
+ match:
+	file->private_data = card->ac97_codec[i];
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int i810_release_mixdev(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const*/ struct file_operations i810_mixer_fops = {
+	llseek:		i810_llseek,
+	ioctl:		i810_ioctl_mixdev,
+	open:		i810_open_mixdev,
+	release:	i810_release_mixdev,
+};
+
+/* AC97 codec initialisation. */
+static int __init i810_ac97_init(struct i810_card *card)
+{
+	int num_ac97 = 0;
+	int ready_2nd = 0;
+	struct ac97_codec *codec;
+	u16 eid;
+
+	outl(0, card->iobase + GLOB_CNT);
+	udelay(500);
+	outl(1<<1, card->iobase + GLOB_CNT);
+
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		memset(codec, 0, sizeof(struct ac97_codec));
+
+		/* initialize some basic codec information, other fields will be filled
+		   in ac97_probe_codec */
+		codec->private_data = card;
+		codec->id = num_ac97;
+
+		codec->codec_read = i810_ac97_get;
+		codec->codec_write = i810_ac97_set;
+	
+		if (ac97_probe_codec(codec) == 0)
+			break;
+
+		eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
+		
+		if(eid==0xFFFFFF)
+		{
+			printk(KERN_WARNING "i810_audio: no codec attached ?\n");
+			kfree(codec);
+			break;
+		}
+		
+		card->ac97_features = eid;
+				
+		if(!(eid&0x0001))
+			printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");
+			
+		if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
+			printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
+			kfree(codec);
+			break;
+		}
+
+		/* Now check the codec for useful features to make up for 
+		   the dumbness of the 810 hardware engine */
+		   
+		card->ac97_codec[num_ac97] = codec;
+
+		/* if there is no secondary codec at all, don't probe any more */
+		if (!ready_2nd)
+			return num_ac97+1;
+	}
+	return num_ac97;
+}
+
+/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
+   untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+   
+static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+{
+	struct i810_card *card;
+
+	if (!pci_dma_supported(pci_dev, I810_DMA_MASK)) {
+		printk(KERN_ERR "intel810: architecture does not support"
+		       " 32bit PCI busmaster DMA\n");
+		return -ENODEV;
+	}
+
+	if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "i810_audio: out of memory\n");
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(*card));
+
+	card->iobase = pci_dev->resource[1].start;
+	card->ac97base = pci_dev->resource[0].start;
+	card->pci_dev = pci_dev;
+	card->pci_id = pci_id->device;
+	card->irq = pci_dev->irq;
+	card->next = devs;
+	card->magic = I810_CARD_MAGIC;
+	spin_lock_init(&card->lock);
+	devs = card;
+
+	pci_set_master(pci_dev);
+	pci_enable_device(pci_dev);
+
+	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n",
+	       card_names[pci_id->driver_data], card->iobase, card->ac97base, 
+	       card->irq);
+
+	card->alloc_pcm_channel = i810_alloc_pcm_channel;
+	card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
+	card->free_pcm_channel = i810_free_pcm_channel;
+
+	/* claim our iospace and irq */
+	request_region(card->iobase, 64, card_names[pci_id->driver_data]);
+	request_region(card->ac97base, 256, card_names[pci_id->driver_data]);
+
+	if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
+			card_names[pci_id->driver_data], card)) {
+		printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
+		release_region(card->iobase, 64);
+		release_region(card->ac97base, 256);
+		kfree(card);
+		return -ENODEV;
+	}
+	/* register /dev/dsp */
+	if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
+		release_region(card->iobase, 64);
+		release_region(card->ac97base, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+
+
+	/* initialize AC97 codec and register /dev/mixer */
+	if (i810_ac97_init(card) <= 0) {
+		unregister_sound_dsp(card->dev_audio);
+		release_region(card->iobase, 64);
+		release_region(card->ac97base, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+	pci_dev->driver_data = card;
+	pci_dev->dma_mask = I810_DMA_MASK;
+
+//	printk("resetting codec?\n");
+	outl(0, card->iobase + GLOB_CNT);
+	udelay(500);
+//	printk("bringing it back?\n");
+	outl(1<<1, card->iobase + GLOB_CNT);
+	return 0;
+}
+
+static void __exit i810_remove(struct pci_dev *pci_dev)
+{
+	int i;
+	struct i810_card *card = pci_dev->driver_data;
+	/* free hardware resources */
+	free_irq(card->irq, devs);
+	release_region(card->iobase, 64);
+	release_region(card->ac97base, 256);
+
+	/* unregister audio devices */
+	for (i = 0; i < NR_AC97; i++)
+		if (devs->ac97_codec[i] != NULL) {
+			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
+			kfree (card->ac97_codec[i]);
+		}
+	unregister_sound_dsp(card->dev_audio);
+	kfree(card);
+}
+
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("Intel 810 audio support");
+
+#define I810_MODULE_NAME "intel810_audio"
+
+static struct pci_driver i810_pci_driver = {
+	name:		I810_MODULE_NAME,
+	id_table:	i810_pci_tbl,
+	probe:		i810_probe,
+	remove:		i810_remove,
+};
+
+static int __init i810_init_module (void)
+{
+	if (!pci_present())   /* No PCI bus in this machine! */
+		return -ENODEV;
+
+	printk(KERN_INFO "Intel 810 + AC97 Audio, version "
+	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+
+	if (!pci_register_driver(&i810_pci_driver)) {
+		pci_unregister_driver(&i810_pci_driver);
+                return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit i810_cleanup_module (void)
+{
+	pci_unregister_driver(&i810_pci_driver);
+}
+
+module_init(i810_init_module);
+module_exit(i810_cleanup_module);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.3.99-pre5/linux/drivers/sound/maestro.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/maestro.c	Fri Apr 21 16:14:14 2000
@@ -21,7 +21,7 @@
  *	Based heavily on SonicVibes.c:
  *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
- *	Heavily modified by Zach Brown <zab@redhat.com> based on lunch
+ *	Heavily modified by Zach Brown <zab@zabbo.net> based on lunch
  *	with ESS engineers.  Many thanks to Howard Kim for providing 
  *	contacts and hardware.  Honorable mention goes to Eric 
  *	Brombaugh for all sorts of things.  Best regards to the 
@@ -105,8 +105,28 @@
  *	being used now is quite dirty and assumes we're on a uni-processor
  *	machine.  Much of it will need to be cleaned up for SMP ACPI or 
  *	similar.
+ *
+ *	We also pay attention to PCI power management now.  The driver
+ *	will power down units of the chip that it knows aren't needed.
+ *	The WaveProcessor and company are only powered on when people
+ *	have /dev/dsp*s open.  On removal the driver will
+ *	power down the maestro entirely.  There could still be
+ *	trouble with BIOSen that magically change power states 
+ *	themselves, but we'll see.  
  *	
  * History
+ *  (still based on v0.14) Mar 29 2000 - Zach Brown <zab@redhat.com>
+ *	move to 2.3 power management interface, which
+ *		required hacking some suspend/resume/check paths 
+ *	make static compilation work
+ *  v0.14 - Jan 28 2000 - Zach Brown <zab@redhat.com>
+ *	add PCI power management through ACPI regs.
+ *	we now shut down on machine reboot/halt
+ *	leave scary PCI config items alone (isa stuff, mostly)
+ *	enable 1921s, it seems only mine was broke.
+ *	fix swapped left/right pcm dac.  har har.
+ *	up bob freq, increase buffers, fix pointers at underflow
+ *	silly compilation problems
  *  v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
  *	fix nec Versas?  man would that be cool.
  *  v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
@@ -162,13 +182,11 @@
  *	bob freq code, region sanity, jitter sync fix; all from Eric 
  *
  * TODO
- *	some people get indir reg timeouts?
  *	fix bob frequency
  *	endianness
  *	do smart things with ac97 2.0 bits.
  *	docking and dual codecs and 978?
  *	leave 54->61 open
- *	resolve 2.3/2.2 stuff
  *
  *	it also would be fun to have a mode that would not use pci dma at all
  *	but would copy into the wavecache on board memory and use that 
@@ -190,6 +208,7 @@
  #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
  #define SILLY_OFFSET(VMA) ((VMA)->vm_offset)
 
+
 #else
 
  #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start)
@@ -197,6 +216,7 @@
  #define SILLY_MAKE_INIT(FUNC) __init FUNC
  #define SILLY_OFFSET(VMA) ((VMA)->vm_pgoff)
 
+
 #endif
 
 #include <linux/string.h>
@@ -213,15 +233,12 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/reboot.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
 #include <linux/pm.h>
 static int maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *d);
-static int in_suspend=0;
-wait_queue_head_t suspend_queue;
-static void check_suspend(void);
-#define CHECK_SUSPEND check_suspend();
 
 #include "maestro.h"
 
@@ -231,14 +248,18 @@
 
 #ifdef M_DEBUG
 static int debug=0;
-static int dsps_order=0;
 #define M_printk(args...) {if (debug) printk(args);}
 #else
 #define M_printk(x)
 #endif
 
+/* we try to setup 2^(dsps_order) /dev/dsp devices */
+static int dsps_order=0;
+/* wether or not we mess around with power management */
+static int use_pm=2; /* set to 1 for force */
+
 /* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.13"
+#define DRIVER_VERSION "0.14"
 
 #ifndef PCI_VENDOR_ESS
 #define PCI_VENDOR_ESS			0x125D
@@ -282,6 +303,46 @@
 #define NR_APUS		64
 #define NR_APU_REGS	16
 
+/* acpi states */
+enum {
+	ACPI_D0=0,
+	ACPI_D1,
+	ACPI_D2,
+	ACPI_D3
+};
+
+/* bits in the acpi masks */
+#define ACPI_12MHZ	( 1 << 15)
+#define ACPI_24MHZ	( 1 << 14)
+#define ACPI_978	( 1 << 13)
+#define ACPI_SPDIF	( 1 << 12)
+#define ACPI_GLUE	( 1 << 11)
+#define ACPI__10	( 1 << 10) /* reserved */
+#define ACPI_PCIINT	( 1 << 9)
+#define ACPI_HV		( 1 << 8) /* hardware volume */
+#define ACPI_GPIO	( 1 << 7)
+#define ACPI_ASSP	( 1 << 6)
+#define ACPI_SB		( 1 << 5) /* sb emul */
+#define ACPI_FM		( 1 << 4) /* fm emul */
+#define ACPI_RB		( 1 << 3) /* ringbus / aclink */
+#define ACPI_MIDI	( 1 << 2) 
+#define ACPI_GP		( 1 << 1) /* game port */
+#define ACPI_WP		( 1 << 0) /* wave processor */
+
+#define ACPI_ALL	(0xffff)
+#define ACPI_SLEEP	(~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \
+			ACPI_MIDI|ACPI_GP|ACPI_WP))
+#define ACPI_NONE	(ACPI__10)
+
+/* these masks indicate which units we care about at
+	which states */
+u16 acpi_state_mask[] = {
+	[ACPI_D0] = ACPI_ALL,
+	[ACPI_D1] = ACPI_SLEEP,
+	[ACPI_D2] = ACPI_SLEEP,
+	[ACPI_D3] = ACPI_NONE
+};
+
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
@@ -303,6 +364,10 @@
 	[TYPE_MAESTRO2E] = (50000000L / 1024L)
 };
 
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
+
+static struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
+
 /* --------------------------------------------------------------------- */
 
 struct ess_state {
@@ -357,6 +422,7 @@
 
 	/* pointer to each dsp?s piece of the apu->src buffer page */
 	void *mixbuf;
+
 };
 	
 struct ess_card {
@@ -383,6 +449,11 @@
 		unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
 	} mix;
 	
+	int power_regs;
+		
+	int in_suspend;
+	wait_queue_head_t suspend_queue;
+
 	struct ess_state channels[MAX_DSPS];
 	u16 maestro_map[NR_IDRS];	/* Register map */
 	/* we have to store this junk so that we can come back from a
@@ -397,7 +468,7 @@
 	int dmaorder;
 
 	/* hardware resources */
-	struct pci_dev pcidev; /* uck.. */
+	struct pci_dev *pcidev;
 	u32 iobase;
 	u32 irq;
 
@@ -434,6 +505,8 @@
 
 /* --------------------------------------------------------------------- */
 
+static void check_suspend(struct ess_card *card);
+
 static struct ess_card *devs = NULL;
 
 /* --------------------------------------------------------------------- */
@@ -443,14 +516,15 @@
  *	ESS Maestro AC97 codec programming interface.
  */
 	 
-static void maestro_ac97_set(int io, u8 cmd, u16 val)
+static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val)
 {
+	int io = card->iobase;
 	int i;
 	/*
 	 *	Wait for the codec bus to be free 
 	 */
 
-	CHECK_SUSPEND;
+	check_suspend(card);
 	 
 	for(i=0;i<10000;i++)
 	{
@@ -466,13 +540,14 @@
 	mdelay(1);
 }
 
-static u16 maestro_ac97_get(int io, u8 cmd)
+static u16 maestro_ac97_get(struct ess_card *card, u8 cmd)
 {
+	int io = card->iobase;
 	int sanity=10000;
 	u16 data;
 	int i;
 	
-	CHECK_SUSPEND;
+	check_suspend(card);
 	/*
 	 *	Wait for the codec bus to be free 
 	 */
@@ -564,7 +639,7 @@
 	int ret=0;
 	struct ac97_mixer_hw *mh = &ac97_hw[mixer];
 
-	val = maestro_ac97_get(card->iobase , mh->offset);
+	val = maestro_ac97_get(card, mh->offset);
 
 	if(AC97_STEREO_MASK & (1<<mixer)) {
 		/* nice stereo mixers .. */
@@ -605,7 +680,7 @@
 	call with spinlock held */
 	
 /* linear scale -> log */
-unsigned char lin2log[101] = 
+static unsigned char lin2log[101] = 
 {
 0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
 50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
@@ -649,19 +724,19 @@
 	} else if (mixer == SOUND_MIXER_SPEAKER) {
 		val = (((100 - left) * mh->scale) / 100) << 1;
 	} else if (mixer == SOUND_MIXER_MIC) {
-		val = maestro_ac97_get(card->iobase , mh->offset) & ~0x801f;
+		val = maestro_ac97_get(card, mh->offset) & ~0x801f;
 		val |= (((100 - left) * mh->scale) / 100);
 	/*  the low bit is optional in the tone sliders and masking
 		it lets is avoid the 0xf 'bypass'.. */
 	} else if (mixer == SOUND_MIXER_BASS) {
-		val = maestro_ac97_get(card->iobase , mh->offset) & ~0x0f00;
+		val = maestro_ac97_get(card , mh->offset) & ~0x0f00;
 		val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
 	} else if (mixer == SOUND_MIXER_TREBLE)  {
-		val = maestro_ac97_get(card->iobase , mh->offset) & ~0x000f;
+		val = maestro_ac97_get(card , mh->offset) & ~0x000f;
 		val |= (((100 - left) * mh->scale) / 100) & 0x000e;
 	}
 
-	maestro_ac97_set(card->iobase , mh->offset, val);
+	maestro_ac97_set(card , mh->offset, val);
 	
 	M_printk(" -> %x\n",val);
 }
@@ -708,7 +783,7 @@
 static int 
 ac97_recmask_io(struct ess_card *card, int read, int mask) 
 {
-	unsigned int val = ac97_oss_mask[ maestro_ac97_get(card->iobase, 0x1a) & 0x7 ];
+	unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ];
 
 	if (read) return val;
 
@@ -723,7 +798,7 @@
 
 	M_printk("maestro: setting ac97 recmask to 0x%x\n",val);
 
-	maestro_ac97_set(card->iobase,0x1a,val);
+	maestro_ac97_set(card,0x1a,val);
 
 	return 0;
 };
@@ -736,7 +811,7 @@
  *	The PT101 setup is untested.
  */
  
-static u16 maestro_ac97_init(struct ess_card *card, int iobase)
+static u16 maestro_ac97_init(struct ess_card *card)
 {
 	u16 vend1, vend2, caps;
 
@@ -747,13 +822,13 @@
 	card->mix.write_mixer = ac97_write_mixer;
 	card->mix.recmask_io = ac97_recmask_io;
 
-	vend1 = maestro_ac97_get(iobase, 0x7c);
-	vend2 = maestro_ac97_get(iobase, 0x7e);
+	vend1 = maestro_ac97_get(card, 0x7c);
+	vend2 = maestro_ac97_get(card, 0x7e);
 
-	caps = maestro_ac97_get(iobase, 0x00);
+	caps = maestro_ac97_get(card, 0x00);
 
 	printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n",
-		vend1,vend2,caps,maestro_ac97_get(iobase,0x26) & 0xf);
+		vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf);
 
 	if (! (caps & 0x4) ) {
 		/* no bass/treble nobs */
@@ -765,10 +840,14 @@
 	switch ((long)(vend1 << 16) | vend2) {
 	case 0x545200ff:	/* TriTech */
 		/* no idea what this does */
-		maestro_ac97_set(iobase,0x2a,0x0001);
-		maestro_ac97_set(iobase,0x2c,0x0000);
-		maestro_ac97_set(iobase,0x2c,0xffff);
+		maestro_ac97_set(card,0x2a,0x0001);
+		maestro_ac97_set(card,0x2c,0x0000);
+		maestro_ac97_set(card,0x2c,0xffff);
 		break;
+#if 0	/* i thought the problems I was seeing were with
+	the 1921, but apparently they were with the pci board
+	it was on, so this code is commented out.
+	 lets see if this holds true. */
 	case 0x83847609:	/* ESS 1921 */
 		/* writing to 0xe (mic) or 0x1a (recmask) seems
 			to hang this codec */
@@ -776,20 +855,21 @@
 		card->mix.record_sources = 0;
 		card->mix.recmask_io = NULL;
 #if 0	/* don't ask.  I have yet to see what these actually do. */
-		maestro_ac97_set(iobase,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
+		maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
 		udelay(20);
-		maestro_ac97_set(iobase,0x78,0x3002);
+		maestro_ac97_set(card,0x78,0x3002);
 		udelay(20);
-		maestro_ac97_set(iobase,0x78,0x3802);
+		maestro_ac97_set(card,0x78,0x3802);
 		udelay(20);
 #endif
 		break;
+#endif
 	default: break;
 	}
 
-	maestro_ac97_set(iobase, 0x1E, 0x0404);
+	maestro_ac97_set(card, 0x1E, 0x0404);
 	/* null misc stuff */
-	maestro_ac97_set(iobase, 0x20, 0x0000);
+	maestro_ac97_set(card, 0x20, 0x0000);
 
 	return 0;
 }
@@ -923,7 +1003,7 @@
 {
 	unsigned long flags;
 
-	CHECK_SUSPEND;
+	check_suspend(s->card);
 	spin_lock_irqsave(&s->card->lock,flags);
 
 	__maestro_write(s->card,reg,data);
@@ -944,7 +1024,7 @@
 	if(READABLE_MAP & (1<<reg))
 	{
 		unsigned long flags;
-		CHECK_SUSPEND;
+		check_suspend(s->card);
 		spin_lock_irqsave(&s->card->lock,flags);
 
 		__maestro_read(s->card,reg);
@@ -1003,7 +1083,7 @@
 {
 	unsigned long flags;
 	
-	CHECK_SUSPEND;
+	check_suspend(s->card);
 
 	if(channel&ESS_CHAN_HARD)
 		channel&=~ESS_CHAN_HARD;
@@ -1032,7 +1112,7 @@
 	unsigned long flags;
 	u16 v;
 	
-	CHECK_SUSPEND;
+	check_suspend(s->card);
 
 	if(channel&ESS_CHAN_HARD)
 		channel&=~ESS_CHAN_HARD;
@@ -1060,7 +1140,7 @@
 {
 	long ioaddr = s->card->iobase;
 	unsigned long flags;
-	CHECK_SUSPEND;
+	check_suspend(s->card);
 	
 	spin_lock_irqsave(&s->card->lock,flags);
 
@@ -1075,7 +1155,7 @@
 	long ioaddr = s->card->iobase;
 	unsigned long flags;
 	u16 value;
-	CHECK_SUSPEND;
+	check_suspend(s->card);
 	
 	spin_lock_irqsave(&s->card->lock,flags);
 	outw(reg, ioaddr+0x10);
@@ -1198,7 +1278,7 @@
 }	
 
 /* stop output apus */
-extern inline void stop_dac(struct ess_state *s)
+static void stop_dac(struct ess_state *s)
 {
 	/* XXX have to lock around this? */
 	if (! (s->enable & DAC_RUNNING)) return;
@@ -1304,11 +1384,12 @@
 			
 /* XXX think about endianess when writing these registers */
 		M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
-		/* Load the buffer into the wave engine */
+		/* start of sample */
 		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
 		apu_set_register(ess, channel, 5, pa&0xFFFF);
+		/* sample end */
 		apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
-		/* setting loop == sample len */
+		/* setting loop len == sample len */
 		apu_set_register(ess, channel, 7, size);
 		
 		/* clear effects/env.. */
@@ -1328,7 +1409,7 @@
 
 		if(mode&ESS_FMT_STEREO) {
 			/* set panning: left or right */
-			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
+			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10));
 			ess->apu_mode[channel] += 0x10;
 		} else
 			apu_set_register(ess, channel, 10, 0x8F08);
@@ -1539,7 +1620,7 @@
 	int divide;
 	
 	/* XXX make freq selector much smarter, see calc_bob_rate */
-	int freq = 150;		/* requested frequency - calculate what we want here. */
+	int freq = 200; 
 	
 	/* compute ideal interrupt frequency for buffer size & play rate */
 	/* first, find best prescaler value to match freq */
@@ -1647,6 +1728,7 @@
 
 	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
 
+	/* this algorithm is a little nuts.. where did /1000 come from? */
 	bytepersec = rate << sample_shift[fmt];
 	bufs = PAGE_SIZE << db->buforder;
 	if (db->ossfragshift) {
@@ -1675,13 +1757,11 @@
 	memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
 
 	spin_lock_irqsave(&s->lock, flags);
-	if (rec) {
-		ess_rec_setup(s, fmt, s->rateadc, 
-			db->rawbuf, db->numfrag << db->fragshift);
-	} else {
-		ess_play_setup(s, fmt, s->ratedac, 
-			db->rawbuf, db->numfrag << db->fragshift);
-	}
+	if (rec) 
+		ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
+	else 
+		ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
+
 	spin_unlock_irqrestore(&s->lock, flags);
 	db->ready = 1;
 
@@ -1720,8 +1800,7 @@
 		/* oh boy should this all be re-written.  everything in the current code paths think
 		that the various counters/pointers are expressed in bytes to the user but we have
 		two apus doing stereo stuff so we fix it up here.. it propogates to all the various
-		counters from here.  Notice that this means that mono recording is very very
-		broken right now.  */
+		counters from here.  */
 		if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
 			hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize;
 		} else {
@@ -1751,7 +1830,7 @@
 		hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
 		/* the apu only reports the length it has seen, not the
 			length of the memory that has been used (the WP
-			knows that */
+			knows that) */
 		if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
 			hwptr<<=1;
 
@@ -1768,14 +1847,15 @@
 			s->dma_dac.count -= diff;
 /*			M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
 			if (s->dma_dac.count <= 0) {
+				M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count, 
+					hwptr, s->dma_dac.swptr);
 				/* FILL ME 
 				wrindir(s, SV_CIENABLE, s->enable); */
 				/* XXX how on earth can calling this with the lock held work.. */
 				stop_dac(s);
 				/* brute force everyone back in sync, sigh */
 				s->dma_dac.count = 0; 
-				s->dma_dac.swptr = 0; 
-				s->dma_dac.hwptr = 0; 
+				s->dma_dac.swptr = hwptr; 
 				s->dma_dac.error++;
 			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
 				clear_advance(s);
@@ -1783,6 +1863,8 @@
 			}
 			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
 				wake_up(&s->dma_dac.wait);
+/*				printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr, 
+					hwptr);*/
 			}
 		}
 	}
@@ -2023,10 +2105,10 @@
 }
 
 static /*const*/ struct file_operations ess_mixer_fops = {
-	llseek:		ess_llseek,
-	ioctl:		ess_ioctl_mixdev,
-	open:		ess_open_mixdev,
-	release:	ess_release_mixdev,
+	llseek:         ess_llseek,
+	ioctl:          ess_ioctl_mixdev,
+	open:           ess_open_mixdev,
+	release:        ess_release_mixdev,
 };
 
 /* --------------------------------------------------------------------- */
@@ -2153,8 +2235,7 @@
 				goto rec_return_free;
 			}
 			if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
-				if(! in_suspend)
-				printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, 
 				       s->dma_adc.hwptr, s->dma_adc.swptr);
 				stop_adc(s);
@@ -2253,8 +2334,7 @@
 				goto return_free;
 			}
 			if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
-				if(! in_suspend)
-				printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, 
 				       s->dma_dac.hwptr, s->dma_dac.swptr);
 				stop_dac(s);
@@ -2277,6 +2357,7 @@
 			if (!ret) ret = -EFAULT;
 			goto return_free;
 		}
+/*		printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/
 
 		swptr = (swptr + cnt) % s->dma_dac.dmasize;
 
@@ -2294,6 +2375,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct ess_state *s = (struct ess_state *)file->private_data;
@@ -2613,6 +2695,7 @@
 
         case SNDCTL_DSP_SETFRAGMENT:
                 get_user_ret(val, (int *)arg, -EFAULT);
+		M_printk("maestro: SETFRAGMENT: %0x\n",val);
 		if (file->f_mode & FMODE_READ) {
 			s->dma_adc.ossfragshift = val & 0xffff;
 			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
@@ -2678,6 +2761,36 @@
 	wave_set_register(s, 0x01FF , packed_phys);
 }
 
+/* 
+ * this guy makes sure we're in the right power
+ * state for what we want to be doing 
+ */
+static void maestro_power(struct ess_card *card, int tostate)
+{
+	u16 active_mask = acpi_state_mask[tostate];
+	u8 state;
+
+	if(!use_pm) return;
+
+	pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state);
+	state&=3;
+
+	/* make sure we're in the right state */
+	if(state != tostate) {
+		M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n",
+			card->pcidev->bus->number, 
+			PCI_SLOT(card->pcidev->devfn),
+			PCI_FUNC(card->pcidev->devfn),
+			state,tostate);
+		pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate);
+	}
+
+	/* and make sure the units we care about are on 
+		XXX we might want to do this before state flipping? */
+	pci_write_config_word(card->pcidev, 0x54, ~ active_mask);
+	pci_write_config_word(card->pcidev, 0x56, ~ active_mask);
+}
+
 /* we allocate a large power of two for all our memory.
 	this is cut up into (not to scale :):
 	|silly fifo word	| 512byte mixbuf per adc	| dac/adc * channels |
@@ -2690,7 +2803,7 @@
 	unsigned long mapend,map;
 
 	/* alloc as big a chunk as we can */
-	for (order = (dsps_order + (15-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
+	for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
 		if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
 			break;
 
@@ -2709,12 +2822,6 @@
 	s->card->dmapages = rawbuf;
 	s->card->dmaorder = order;
 
-	/* play bufs are in the same first region as record bufs */
-	set_base_registers(s,rawbuf);
-
-	M_printk("maestro: writing %lx (%lx) to the wp\n",virt_to_bus(rawbuf),
-		((virt_to_bus(rawbuf))&0xFFE00000)>>12);
-
 	for(i=0;i<NR_DSPS;i++) {
 		struct ess_state *ess = &s->card->channels[i];
 
@@ -2733,7 +2840,7 @@
 			happily scribble away.. */ 
 		ess->mixbuf = rawbuf + (512 * (i+1));
 
-		M_printk("maestro: setup apu %d: %p %p %p\n",i,ess->dma_dac.rawbuf,
+		M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf,
 			ess->dma_adc.rawbuf, ess->mixbuf);
 
 	}
@@ -2819,6 +2926,20 @@
 		return -ENOMEM;
 	}
 
+	/* we're covered by the open_sem */
+	if( ! s->card->dsps_open )  {
+		maestro_power(s->card,ACPI_D0);
+		start_bob(s);
+	}
+	s->card->dsps_open++;
+	M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
+
+	/* ok, lets write WC base regs now that we've 
+		powered up the chip */
+	M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages),
+		((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12);
+	set_base_registers(s,s->card->dmapages);
+
 	if (file->f_mode & FMODE_READ) {
 /*
 		fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
@@ -2842,13 +2963,6 @@
 	set_fmt(s, fmtm, fmts);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 
-	/* we're covered by the open_sem */
-	if( ! s->card->dsps_open )  {
-		start_bob(s);
-	}
-	s->card->dsps_open++;
-	M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
-
 	up(&s->open_sem);
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -2874,8 +2988,10 @@
 	/* we're covered by the open_sem */
 	M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
 	if( --s->card->dsps_open <= 0) {
+		s->card->dsps_open = 0;
 		stop_bob(s);
 		free_buffers(s);
+		maestro_power(s->card,ACPI_D2);
 	}
 	up(&s->open_sem);
 	wake_up(&s->open_wait);
@@ -2884,56 +3000,42 @@
 }
 
 static struct file_operations ess_audio_fops = {
-	llseek:		ess_llseek,
-	read:		ess_read,
-	write:		ess_write,
-	poll:		ess_poll,
-	ioctl:		ess_ioctl,
-	mmap:		ess_mmap,
-	open:		ess_open,
-	release:	ess_release,
+	llseek:         ess_llseek,
+	read:           ess_read,
+	write:          ess_write,
+	poll:           ess_poll,
+	ioctl:          ess_ioctl,
+	mmap:           ess_mmap,
+	open:           ess_open,
+	release:        ess_release,
 };
 
 static int
 maestro_config(struct ess_card *card) 
 {
-	struct pci_dev *pcidev = &card->pcidev;
+	struct pci_dev *pcidev = card->pcidev;
 	struct ess_state *ess = &card->channels[0];
 	int apu,iobase  = card->iobase;
 	u16 w;
 	u32 n;
 
-	/*
-	 *	Disable ACPI
+	/* We used to muck around with pci config space that
+	 * we had no business messing with.  We don't know enough
+	 * about the machine to know which DMA mode is appropriate, 
+	 * etc.  We were guessing wrong on some machines and making
+	 * them unhappy.  We now trust in the BIOS to do things right,
+	 * which almost certainly means a new host of problems will
+	 * arise with broken BIOS implementations.  screw 'em. 
+	 * We're already intolerant of machines that don't assign
+	 * IRQs.
 	 */
-	 
-	pci_write_config_dword(pcidev, 0x54, 0x00000000);
-	pci_write_config_dword(pcidev, 0x56, 0x00000000);
 	
-	/*
-	 *	Use TDMA for now. TDMA works on all boards, so while its
-	 *	not the most efficient its the simplest.
-	 */ 
+	/* do config work at full power */
+	maestro_power(card,ACPI_D0);
 	 
 	pci_read_config_word(pcidev, 0x50, &w);
 
-	/* Clear DMA bits */
-	w&=~(1<<10|1<<9|1<<8);
-
-	/* TDMA on */
-	w|= (1<<8);
-
-	/*
-	 *	Some of these are undocumented bits
-	 */
-	 
-	w&=~(1<<13)|(1<<14);		/* PIC Snoop mode bits */
-	w&=~(1<<11);			/* Safeguard off */
-	w|= (1<<7);			/* Posted write */
-	w|= (1<<6);			/* ISA timing on */
-	/* XXX huh?  claims to be reserved.. */
-	w&=~(1<<5);			/* Don't swap left/right */
-	w&=~(1<<1);			/* Subtractive decode off */
+	w&=~(1<<5);			/* Don't swap left/right (undoc)*/
 	
 	pci_write_config_word(pcidev, 0x50, w);
 	
@@ -2946,19 +3048,9 @@
 	w&=~(1<<6);		/* Debounce off */
 	w&=~(1<<5);		/* GPIO 4:5 */
 	w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
-	w&=~(1<<3);		/* IDMA off (undocumented) */
 	w&=~(1<<2);		/* MIDI fix off (undoc) */
 	w&=~(1<<1);		/* reserved, always write 0 */
-	w&=~(1<<0);		/* IRQ to ISA off (undoc) */
 	pci_write_config_word(pcidev, 0x52, w);
-
-	/*
-	 *	DDMA off
-	 */
-
-	pci_read_config_word(pcidev, 0x60, &w);
-	w&=~(1<<0);
-	pci_write_config_word(pcidev, 0x60, w);
 	
 	/*
 	 *	Legacy mode
@@ -2971,8 +3063,6 @@
 	 
 	pci_write_config_word(pcidev, 0x40, w);
 
-	/* stake our claim on the iospace */
-	request_region(iobase, 256, card_names[card->card_type]);
 	
 	sound_reset(iobase);
 
@@ -3140,6 +3230,39 @@
 	
 }
 
+/* this guy tries to find the pci power management
+ * register bank.  this should really be in core
+ * code somewhere.  1 on success. */
+int
+parse_power(struct ess_card *card, struct pci_dev *pcidev)
+{
+	u32 n;
+	u16 w;
+	u8 next;
+	int max = 64;  /* an a 8bit guy pointing to 32bit guys
+				can only express so much. */
+
+	card->power_regs = 0;
+
+	/* check to see if we have a capabilities list in
+		the config register */
+	pci_read_config_word(pcidev, PCI_STATUS, &w);
+	if(! w & PCI_STATUS_CAP_LIST) return 0;
+
+	/* walk the list, starting at the head. */
+	pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next);
+
+	while(next && max--) {
+		pci_read_config_dword(pcidev, next & ~3, &n);
+		if((n & 0xff) == PCI_CAP_ID_PM) {
+			card->power_regs = next;
+			break;
+		}
+		next = ((n>>8) & 0xff);
+	}
+
+	return card->power_regs ? 1 : 0;
+}
 
 static int 
 maestro_install(struct pci_dev *pcidev, int card_type)
@@ -3149,7 +3272,7 @@
 	int i;
 	struct ess_card *card;
 	struct ess_state *ess;
-        struct pm_dev *pmdev;
+	struct pm_dev *pmdev;
 	int num = 0;
 
 	/* don't pick up weird modem maestros */
@@ -3158,15 +3281,15 @@
 			
 	iobase = SILLY_PCI_BASE_ADDRESS(pcidev); 
 
-	if(check_region(iobase, 256))
+	/* stake our claim on the iospace */
+	if( request_region(iobase, 256, card_names[card_type]) == NULL )
 	{
 		printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
 		return 0;
 	}
 
 	/* this was tripping up some machines */
-	if(pcidev->irq == 0) 
-	{
+	if(pcidev->irq == 0) {
 		printk(KERN_WARNING "maestro: pci subsystem reports irq 0, this might not be correct.\n");
 	}
 
@@ -3181,13 +3304,16 @@
 	}
 	
 	memset(card, 0, sizeof(*card));
-	memcpy(&card->pcidev,pcidev,sizeof(card->pcidev));
+	card->pcidev = pcidev;
 
-	pmdev = pm_register(PM_PCI_DEV,
-                            PM_PCI_ID(pcidev),
-                            maestro_pm_callback);
-        if (pmdev)
-                pmdev->data = card;
+	pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pcidev),
+			maestro_pm_callback);
+	if (pmdev)
+		pmdev->data = card;
+
+	if (register_reboot_notifier(&maestro_nb)) {
+		printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
+	}
 
 	card->iobase = iobase;
 	card->card_type = card_type;
@@ -3195,6 +3321,7 @@
 	card->next = devs;
 	card->magic = ESS_CARD_MAGIC;
 	spin_lock_init(&card->lock);
+	init_waitqueue_head(&card->suspend_queue);
 	devs = card;
 	
 	/* init our groups of 6 apus */
@@ -3246,13 +3373,37 @@
 	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
 	printk(KERN_INFO "maestro:  subvendor id: 0x%08x\n",n); 
 
+	/* turn off power management unless:
+	 *	- the user explicitly asks for it
+	 * 		or
+	 *		- we're not a 2e, lesser chipps seem to have problems.
+	 *		- we're not on our _very_ small whitelist.  some implemenetations
+	 *			really dont' like the pm code, others require it.
+	 *			feel free to expand this as required.
+	 */
+#define SUBSYSTEM_VENDOR(x) (x&0xffff)
+	if(	(use_pm != 1) && 
+		((card_type != TYPE_MAESTRO2E)	|| (SUBSYSTEM_VENDOR(n) != 0x1028)))
+			use_pm = 0;
+
+	if(!use_pm) 
+		printk(KERN_INFO "maestro: not attempting power management.\n");
+	else {
+		if(!parse_power(card,pcidev)) 
+			printk(KERN_INFO "maestro: no PCI power managment interface found.\n");
+		else {
+			pci_read_config_dword(pcidev, card->power_regs, &n);
+			printk(KERN_INFO "maestro: PCI power managment capability: 0x%x\n",n>>16);
+		}	
+	}
+
 	maestro_config(card);
 
-	if(maestro_ac97_get(iobase, 0x00)==0x0080) {
+	if(maestro_ac97_get(card, 0x00)==0x0080) {
 		printk(KERN_ERR "maestro: my goodness!  you seem to have a pt101 codec, which is quite rare.\n"
 				"\tyou should tell someone about this.\n");
 	} else {
-		maestro_ac97_init(card,iobase);
+		maestro_ac97_init(card);
 	}
 
 	if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) {
@@ -3273,9 +3424,12 @@
 				unregister_sound_dsp(s->dev_audio);
 		}
 		release_region(card->iobase, 256);		
+		unregister_reboot_notifier(&maestro_nb);
 		kfree(card);
 		return 0;
 	}
+	/* now go to sleep 'till something interesting happens */
+	maestro_power(card,ACPI_D2);
 
 	printk(KERN_INFO "maestro: %d channels configured.\n", num);
 	return 1; 
@@ -3305,8 +3459,6 @@
 		printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
 	}
 
-	init_waitqueue_head(&suspend_queue);
-
 	/*
 	 *	Find the ESS Maestro 2.
 	 */
@@ -3340,56 +3492,78 @@
 	return 0;
 }
 
-/* --------------------------------------------------------------------- */
-
-#ifdef MODULE
-MODULE_AUTHOR("Zach Brown <zab@redhat.com>, Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("ESS Maestro Driver");
-#ifdef M_DEBUG
-MODULE_PARM(debug,"i");
-#endif
-MODULE_PARM(dsps_order,"i");
-
-void cleanup_module(void)
+static void nuke_maestros(void)
 {
-	struct ess_card *s;
+	struct ess_card *card;
 
+	/* we do these unconditionally, which is probably wrong */
 	pm_unregister_all(maestro_pm_callback);
+	unregister_reboot_notifier(&maestro_nb);
 
-	while ((s = devs)) {
+	while ((card = devs)) {
 		int i;
 		devs = devs->next;
 	
 		/* XXX maybe should force stop bob, but should be all 
 			stopped by _release by now */
-		free_irq(s->irq, s);
-		unregister_sound_mixer(s->dev_mixer);
+		free_irq(card->irq, card);
+		unregister_sound_mixer(card->dev_mixer);
 		for(i=0;i<NR_DSPS;i++)
 		{
-			struct ess_state *ess = &s->channels[i];
+			struct ess_state *ess = &card->channels[i];
 			if(ess->dev_audio != -1)
 				unregister_sound_dsp(ess->dev_audio);
 		}
-		release_region(s->iobase, 256);
-		kfree(s);
+		/* Goodbye, Mr. Bond. */
+		maestro_power(card,ACPI_D3);
+		release_region(card->iobase, 256);
+		kfree(card);
 	}
+	devs = NULL;
+}
+
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+{
+	/* this notifier is called when the kernel is really shut down. */
+	M_printk("maestro: shutting down\n");
+	nuke_maestros();
+	return NOTIFY_OK;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>");
+MODULE_DESCRIPTION("ESS Maestro Driver");
+#ifdef M_DEBUG
+MODULE_PARM(debug,"i");
+#endif
+MODULE_PARM(dsps_order,"i");
+MODULE_PARM(use_pm,"i");
+
+void cleanup_module(void) {
 	M_printk("maestro: unloading\n");
+	nuke_maestros();
 }
 
-#endif /* MODULE */
+#else /* MODULE */
+__initcall(init_maestro);
+#endif
+
+/* --------------------------------------------------------------------- */
 
 void
-check_suspend(void)
+check_suspend(struct ess_card *card)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	if(!in_suspend) return;
+	if(!card->in_suspend) return;
 
-	in_suspend++;
-	add_wait_queue(&suspend_queue, &wait);
+	card->in_suspend++;
+	add_wait_queue(&(card->suspend_queue), &wait);
 	current->state = TASK_UNINTERRUPTIBLE;
 	schedule();
-	remove_wait_queue(&suspend_queue, &wait);
+	remove_wait_queue(&(card->suspend_queue), &wait);
 	current->state = TASK_RUNNING;
 }
 
@@ -3397,113 +3571,138 @@
 maestro_suspend(struct ess_card *card)
 {
 	unsigned long flags;
-        int i,j;
+	int i,j;
 
-	save_flags(flags);
-	cli();
+	save_flags(flags); 
+	cli(); /* over-kill */
 
-        M_printk("maestro: pm in dev %p\n",card);
+	M_printk("maestro: apm in dev %p\n",card);
 
-        for(i=0;i<NR_DSPS;i++) {
-                struct ess_state *s = &card->channels[i];
+	/* we have to read from the apu regs, need
+		to power it up */
+	maestro_power(card,ACPI_D0);
 
-                if(s->dev_audio == -1)
-                        continue;
-                
-                M_printk("maestro: stopping apus for device %d\n",i);
-                stop_dac(s);
-                stop_adc(s);
-                for(j=0;j<6;j++) 
-                        card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5);
-                
-        }
+	for(i=0;i<NR_DSPS;i++) {
+		struct ess_state *s = &card->channels[i];
 
-        /* get rid of interrupts? */
-        if( card->dsps_open > 0)
-                stop_bob(&card->channels[0]);
+		if(s->dev_audio == -1)
+			continue;
 
-        in_suspend=1;
+		M_printk("maestro: stopping apus for device %d\n",i);
+		stop_dac(s);
+		stop_adc(s);
+		for(j=0;j<6;j++) 
+			card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5);
 
-	restore_flags(flags);
+	}
+
+	/* get rid of interrupts? */
+	if( card->dsps_open > 0)
+		stop_bob(&card->channels[0]);
 
-	/* we'll let the bios do the rest of the power down.. */
+	card->in_suspend++;
 
+	restore_flags(flags);
+
+	/* we trust in the bios to power down the chip on suspend.
+	 * XXX I'm also not sure that in_suspend will protect
+	 * against all reg accesses from here on out. 
+	 */
 	return 0;
 }
 static int 
 maestro_resume(struct ess_card *card)
 {
 	unsigned long flags;
-        int i;
+	int i;
 
 	save_flags(flags);
-	cli();
-	in_suspend=0;
-	M_printk("maestro: resuming\n");
-
-	/* first lets just bring everything back. .*/
-
-        M_printk("maestro: pm in dev %p\n",card);
-
-        maestro_config(card);
-        /* need to restore the base pointers.. */ 
-        if(card->dmapages) 
-                set_base_registers(&card->channels[0],card->dmapages);
-        
-        mixer_push_state(card);
-        
-        for(i=0;i<NR_DSPS;i++) {
-                struct ess_state *s = &card->channels[i];
-                int chan,reg;
-                
-                if(s->dev_audio == -1)
-                        continue;
-                
-                for(chan = 0 ; chan < 6 ; chan++) {
-                        wave_set_register(s,s->apu[chan]<<3,s->apu_base[chan]);
-                        for(reg = 1 ; reg < NR_APU_REGS ; reg++)  
-                                apu_set_register(s,chan,reg,s->card->apu_map[s->apu[chan]][reg]);
-                }
-                for(chan = 0 ; chan < 6 ; chan++)  
-                        apu_set_register(s,chan,0,s->card->apu_map[s->apu[chan]][0] & 0xFF0F);
-        }
+	cli(); /* over-kill */
+
+	card->in_suspend = 0;
+
+	M_printk("maestro: resuming card at %p\n",card);
+
+	/* restore all our config */
+	maestro_config(card);
+	/* need to restore the base pointers.. */ 
+	if(card->dmapages) 
+		set_base_registers(&card->channels[0],card->dmapages);
+
+	mixer_push_state(card);
+
+	/* set each channels' apu control registers before
+	 * restoring audio 
+	 */
+	for(i=0;i<NR_DSPS;i++) {
+		struct ess_state *s = &card->channels[i];
+		int chan,reg;
+
+		if(s->dev_audio == -1)
+			continue;
+
+		for(chan = 0 ; chan < 6 ; chan++) {
+			wave_set_register(s,s->apu[chan]<<3,s->apu_base[chan]);
+			for(reg = 1 ; reg < NR_APU_REGS ; reg++)  
+				apu_set_register(s,chan,reg,s->card->apu_map[s->apu[chan]][reg]);
+		}
+		for(chan = 0 ; chan < 6 ; chan++)  
+			apu_set_register(s,chan,0,s->card->apu_map[s->apu[chan]][0] & 0xFF0F);
+	}
 
 	/* now we flip on the music */
-        M_printk("maestro: pm in dev %p\n",card);
 
-        for(i=0;i<NR_DSPS;i++) {
-                struct ess_state *s = &card->channels[i];
-                
-                /* these use the apu_mode, and can handle
-                   spurious calls */
-                start_dac(s);	
-                start_adc(s);	
-        }
-        if( card->dsps_open > 0)
-                start_bob(&card->channels[0]);
+	if( card->dsps_open <= 0) {
+		/* this card's idle */
+		maestro_power(card,ACPI_D2);
+	} else {
+		/* ok, we're actually playing things on
+			this card */
+		maestro_power(card,ACPI_D0);
+		start_bob(&card->channels[0]);
+		for(i=0;i<NR_DSPS;i++) {
+			struct ess_state *s = &card->channels[i];
+
+			/* these use the apu_mode, and can handle
+				spurious calls */
+			start_dac(s);	
+			start_adc(s);	
+		}
+	}
 
 	restore_flags(flags);
 
-	wake_up(&suspend_queue);
+	/* all right, we think things are ready, 
+		wake up people who were using the device
+		when we suspended */
+	wake_up(&(card->suspend_queue));
 
 	return 0;
 }
 
 int 
-maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
-        struct ess_card *card = (struct ess_card*) dev->data;
-        if (card) {
-                M_printk("maestro: pm event received: 0x%x\n", rqst);
-
-                switch (rqst) {
-                case PM_SUSPEND: 
-                        maestro_suspend(card);
-                        break;
-                case PM_RESUME: 
-                        maestro_resume(card);
-                        break;
-                }
-        }
+maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) 
+{
+	struct ess_card *card = (struct ess_card*) dev->data;
+
+	if ( ! card ) goto out;
 
+	M_printk("maestro: pm event 0x%x received for card %p\n", rqst, card);
+	
+	switch (rqst) {
+		case PM_SUSPEND: 
+			maestro_suspend(card);
+		break;
+		case PM_RESUME: 
+			maestro_resume(card);
+		break;
+		/*
+		 * we'd also like to find out about
+		 * power level changes because some biosen
+		 * do mean things to the maestro when they
+		 * change their power state.
+		 */
+        }
+out:
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v2.3.99-pre5/linux/drivers/sound/midibuf.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/midibuf.c	Fri Apr 21 13:28:34 2000
@@ -394,6 +394,7 @@
 	}
 }
 
+/* No kernel lock - fine */
 unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
 {
 	unsigned int mask = 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.3.99-pre5/linux/drivers/sound/sb_card.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/sb_card.c	Fri Apr 14 10:09:51 2000
@@ -10,7 +10,6 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  *
- *
  * 26-11-1999 Patched to compile without ISA PnP support in the
  * kernel - Daniel Stone (tamriel@ductape.net) 
  *
@@ -37,6 +36,10 @@
  * 26-03-2000 Fixed acer, esstype and sm_games module options.
  *  Alessandro Zummo <azummo@ita.flashnet.it>
  *
+ * 12-04-2000 ISAPnP cleanup, reorg, fixes, and multiple card support.
+ *  Thanks to Gaël Quéri and Alessandro Zummo for testing and fixes.
+ *  Paul E. Laufer <pelaufer@csupomona.edu>
+ *
  */
 
 #include <linux/config.h>
@@ -51,7 +54,14 @@
 #include "sb_mixer.h"
 #include "sb.h"
 
-static int sbmpu = 0;
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+#define SB_CARDS_MAX 4
+#else
+#define SB_CARDS_MAX 1
+#endif
+
+static int sbmpu[SB_CARDS_MAX] = {0};
+static int sb_cards_num = 0;
 
 extern void *smw_free;
 
@@ -75,7 +85,6 @@
 {
 	if(!sb_dsp_init(hw_config))
 		hw_config->slots[0] = -1;
-	SOUND_LOCK;
 }
 
 static int __init probe_sb(struct address_info *hw_config)
@@ -84,7 +93,7 @@
 
 	if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1)
 	{
-		printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
+		printk(KERN_ERR "sb: I/O, IRQ, and DMA are mandatory\n");
 		return -EINVAL;
 	}
 
@@ -149,14 +158,6 @@
 	}
 #endif
 
-	/* This is useless since it is done by sb_dsp_detect - azummo */
-	
-	if (check_region(hw_config->io_base, 16))
-	{
-		printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base);
-		return 0;
-	}
-
 	/* Setup extra module options */
 
 	sbmo.acer 	= acer;
@@ -166,25 +167,33 @@
 	return sb_dsp_detect(hw_config, 0, 0, &sbmo);
 }
 
-static void __exit unload_sb(struct address_info *hw_config)
+static void __exit unload_sb(struct address_info *hw_config, int card)
 {
 	if(hw_config->slots[0]!=-1)
-		sb_dsp_unload(hw_config, sbmpu);
+		sb_dsp_unload(hw_config, sbmpu[card]);
 }
 
-static struct address_info cfg;
-static struct address_info cfg_mpu;
+static struct address_info cfg[SB_CARDS_MAX];
+static struct address_info cfg_mpu[SB_CARDS_MAX];
 
-struct pci_dev 	*sb_dev 	= NULL, 
-		*mpu_dev	= NULL;
+struct pci_dev 	*sb_dev[SB_CARDS_MAX] 	= {NULL}, 
+		*mpu_dev[SB_CARDS_MAX]	= {NULL},
+		*opl_dev[SB_CARDS_MAX]	= {NULL};
 
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 static int isapnp	= 1;
 static int isapnpjump	= 0;
-static int activated	= 1;
+static int multiple	= 0;
+static int reverse	= 0;
+static int uart401	= 0;
+
+static int audio_activated[SB_CARDS_MAX] = {0};
+static int mpu_activated[SB_CARDS_MAX]   = {0};
+static int opl_activated[SB_CARDS_MAX]   = {0};
 #else
 static int isapnp	= 0;
+static int multiple	= 1;
 #endif
 
 MODULE_DESCRIPTION("Soundblaster driver");
@@ -202,8 +211,14 @@
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 MODULE_PARM(isapnp,	"i");
 MODULE_PARM(isapnpjump,	"i");
+MODULE_PARM(multiple,	"i");
+MODULE_PARM(reverse,	"i");
+MODULE_PARM(uart401,	"i");
 MODULE_PARM_DESC(isapnp,	"When set to 0, Plug & Play support will be disabled");
 MODULE_PARM_DESC(isapnpjump,	"Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
+MODULE_PARM_DESC(multiple,	"When set to 0, will not search for multiple cards");
+MODULE_PARM_DESC(reverse,	"When set to 1, will reverse ISAPnP search order");
+MODULE_PARM_DESC(uart401,	"When set to 1, will attempt to detect and enable the mpu on some clones");
 #endif
 
 MODULE_PARM_DESC(io,		"Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
@@ -218,6 +233,211 @@
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 
+/* Please add new entries at the end of the table */
+static struct {
+	char *name; 
+	unsigned short	card_vendor, card_device, 
+			audio_vendor, audio_function,
+			mpu_vendor, mpu_function,
+			opl_vendor, opl_function;
+	short dma, dma2, mpu_io, mpu_irq; /* see sb_init() */
+} sb_isapnp_list[] __initdata = {
+	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0024),
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0026), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0027), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0029), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster Vibra16S", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster Vibra16C", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0070), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster Vibra16CL", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0080), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster Vibra16X", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00F0), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0039), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0042), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0043), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0044),
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0054), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009C), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 64",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009D), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 64 Gold",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009E), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 64",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C1), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 64",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C3), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 64",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C5), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 64",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C7), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 64",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E4), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
+		0,0,0,0,
+		0,1,1,-1},
+	{"ESS 1868",
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868), 
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868),
+		0,0,0,0,
+		0,1,2,-1},
+	{"ESS 1868",
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868), 
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611),
+		0,0,0,0,
+		0,1,2,-1},
+	{"ESS 1869 PnP AudioDrive", 
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0003), 
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869),
+		0,0,0,0,
+		0,1,2,-1},
+	{"ESS 1869",
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1869), 
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869),
+		0,0,0,0,
+		0,1,2,-1},
+	{"ESS 1878",
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1878), 
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878),
+		0,0,0,0,
+		0,1,2,-1},
+	{"ESS 1879",
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1879), 
+		ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879),
+		0,0,0,0,
+		0,1,2,-1},
+	{"CMI 8330 SoundPRO",
+		ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), 
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
+		0,1,0,-1},
+	{"Diamond DT0197H",
+		ISAPNP_VENDOR('R','W','B'), ISAPNP_DEVICE(0x1688), 
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		0,-1,0,0},
+	{"ALS007",
+		ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0007),
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		0,-1,0,0},
+	{"ALS100",
+	       	ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001), 
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		1,0,0,0},
+	{"ALS110",
+		ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0110),
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x1001),
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x1001),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		1,0,0,0},
+	{"ALS120",
+		ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0120),
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001),
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		1,0,0,0},
+	{"ALS200",
+		ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0200),
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0020),
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0020),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		1,0,0,0},
+	{"RTL3000",
+		ISAPNP_VENDOR('R','T','L'), ISAPNP_DEVICE(0x3000),
+		ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001),
+		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001),
+		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
+		1,0,0,0},
+	{0}
+};
+
 /* That's useful. */
 
 #define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start)
@@ -227,14 +447,10 @@
 	int err;
 
 	/* Device already active? Let's use it */
-
 	if(dev->active)
-	{
-		activated = 0;
 		return(dev);
-	}
-	if((err = dev->activate(dev)) < 0)
-	{
+	
+	if((err = dev->activate(dev)) < 0) {
 		printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err);
 
 		dev->deactivate(dev);
@@ -244,320 +460,153 @@
 	return(dev);
 }
 
-/* Card's specific initialization functions
- */
-
-static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init(struct pci_bus *bus, struct address_info *hw_config, struct address_info *mpu_config, int slot, int card)
 {
-	if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
-	{
-		sb_dev->prepare(sb_dev);
-
-		if((sb_dev = activate_dev("Soundblaster", "sb", sb_dev)))
-		{
-			hw_config->io_base 	= sb_dev->resource[0].start;
-			hw_config->irq 		= sb_dev->irq_resource[0].start;
-			hw_config->dma 		= sb_dev->dma_resource[0].start;
-			hw_config->dma2 	= sb_dev->dma_resource[1].start;
-			mpu_config->io_base	= sb_dev->resource[1].start;
-		}
-	}
-	return(sb_dev);
-}
 
-static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
-{
-	if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
+	/* Configure Audio device */
+	if((sb_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].audio_vendor, sb_isapnp_list[slot].audio_function, NULL)))
 	{
-		sb_dev->prepare(sb_dev);
-
-		if((sb_dev = activate_dev("ESS", "sb", sb_dev)))
-		{
-			hw_config->io_base 	= sb_dev->resource[0].start;
-			hw_config->irq 		= sb_dev->irq_resource[0].start;
-			hw_config->dma 		= sb_dev->dma_resource[0].start;
-			hw_config->dma2		= sb_dev->dma_resource[1].start;
-			mpu_config->io_base	= sb_dev->resource[2].start;
+		int ret;
+		ret = sb_dev[card]->prepare(sb_dev[card]);
+		/* If device is active, assume configured with /proc/isapnp
+		 * and use anyway. Some other way to check this? */
+		if(ret && ret != -EBUSY) {
+			printk(KERN_ERR "sb: ISAPnP found device that could not be autoconfigured.\n");
+			return(NULL);
 		}
-	}
-	return(sb_dev);
-}
-
-static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
-{
-	/* 
-	 *  The CMI8330/C3D is a very 'stupid' chip... where did they get al those @@@ ?
-	 *  It's ISAPnP section is badly designed and has many flaws, i'll do my best
-	 *  to workaround them. I strongly suggest you to buy a real soundcard.
-	 *  The CMI8330 on my motherboard has also the bad habit to activate 
-	 *  the rear channel of my amplifier instead of the front one.
-	 */
-
-	/*  @X@0001:Soundblaster.
-	 */
-
-	if((sb_dev = isapnp_find_dev(bus,
-		ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-	{
-		sb_dev->prepare(sb_dev);
+		if(ret == -EBUSY)
+			audio_activated[card] = 1;
 		
-		if((sb_dev = activate_dev("CMI8330", "sb", sb_dev)))
+		if((sb_dev[card] = activate_dev(sb_isapnp_list[slot].name, "sb", sb_dev[card])))
 		{
-			hw_config->io_base 	= sb_dev->resource[0].start;
-			hw_config->irq 		= sb_dev->irq_resource[0].start;
-			hw_config->dma 		= sb_dev->dma_resource[0].start;
-			hw_config->dma2 	= sb_dev->dma_resource[1].start;
+			hw_config->io_base 	= sb_dev[card]->resource[0].start;
+			hw_config->irq 		= sb_dev[card]->irq_resource[0].start;
+			hw_config->dma 		= sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma].start;
+			if(sb_isapnp_list[slot].dma2 != -1)
+				hw_config->dma2 = sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma2].start;
+			else
+				hw_config->dma2 = -1;
+		} else
+			return(NULL);
+	} else
+		return(NULL);
 
-			show_base("CMI8330", "sb", &sb_dev->resource[0]);
-		}
+	/* Cards with separate OPL3 device (ALS, CMI, etc.)
+	 * This is just to activate the device... */
+	if(sb_isapnp_list[slot].opl_vendor || sb_isapnp_list[slot].opl_function) {
+		if((opl_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].opl_vendor, sb_isapnp_list[slot].opl_function, NULL))) {
+			int ret = opl_dev[card]->prepare(opl_dev[card]);
+			/* If device is active, assume configured with
+			 * /proc/isapnp and use anyway */
+			if(ret && ret != -EBUSY) {
+				printk(KERN_ERR "sb: OPL device could not be autoconfigured.\n");
+				return(sb_dev[card]);
+			}
+			if(ret == -EBUSY)
+				opl_activated[card] = 1;
 
-		if(!sb_dev) return(NULL);
+			/* Some have irq and dma for opl. the opl3 driver wont
+			 * use 'em so don't configure 'em and hope it works -PEL */
+			opl_dev[card]->irq_resource[0].flags = 0;
+			opl_dev[card]->dma_resource[0].flags = 0;
+
+			opl_dev[card] = activate_dev(sb_isapnp_list[slot].name, "opl3", opl_dev[card]);
+		} else
+			printk(KERN_ERR "sb: %s isapnp panic: opl3 device not found\n", sb_isapnp_list[slot].name);
+	}
+
+	/* Cards with MPU as part of Audio device (CTL and ESS) */
+	if(!sb_isapnp_list[slot].mpu_vendor) {
+		mpu_config->io_base	= sb_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start;
+		return(sb_dev[card]);
 	}
-	else
-		printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n");
-
-	/*  @H@0001:mpu
-	 */
-
-	if((mpu_dev = isapnp_find_dev(bus,
-		ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-	{
-		mpu_dev->prepare(mpu_dev);
-
-		/*  This disables the interrupt on this resource. Do we need it ?
-		 */
-
-		mpu_dev->irq_resource[0].flags = 0;
-
-		if((mpu_dev = activate_dev("CMI8330", "mpu", mpu_dev)))
-		{
-			show_base("CMI8330", "mpu", &mpu_dev->resource[0]);
-			mpu_config->io_base = mpu_dev->resource[0].start;
+	
+	/* Cards with separate MPU device (ALS, CMI, etc.) */
+	if(!uart401)
+		return(sb_dev[card]);
+	if((mpu_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].mpu_vendor, sb_isapnp_list[slot].mpu_function, NULL)))
+	{
+		int ret = mpu_dev[card]->prepare(mpu_dev[card]);
+		/* If device is active, assume configured with /proc/isapnp
+		 * and use anyway */
+		if(ret && ret != -EBUSY) {
+			printk(KERN_ERR "sb: MPU device could not be autoconfigured.\n");
+			return(sb_dev[card]);
 		}
-	}
-	else
-		printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n");
-
-	printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
-
-	return(sb_dev);
-}
-
-static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
-{
-	/* 
-	 * Diamonds DT0197H
-	 * very similar to the CMI8330 above
-	 */
-
-	/*  @@@0001:Soundblaster.
-	 */
-
-	if((sb_dev = isapnp_find_dev(bus,
-				ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-	{
-		sb_dev->prepare(sb_dev);
+		if(ret == -EBUSY)
+			mpu_activated[card] = 1;
 		
-		if((sb_dev = activate_dev("DT0197H", "sb", sb_dev)))
-		{
-			hw_config->io_base 	= sb_dev->resource[0].start;
-			hw_config->irq 		= sb_dev->irq_resource[0].start;
-			hw_config->dma 		= sb_dev->dma_resource[0].start;
-			hw_config->dma2 	= -1;
-
-			show_base("DT0197H", "sb", &sb_dev->resource[0]);
-		}
-
-		if(!sb_dev) return(NULL);
-	}
-	else
-		printk(KERN_ERR "sb: DT0197H panic: sb base not found\n");
-
-	/*  @X@0001:mpu
-	 */
-
-	if((mpu_dev = isapnp_find_dev(bus,
-				ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-	{
-		mpu_dev->prepare(mpu_dev);
-
-		if((mpu_dev = activate_dev("DT0197H", "mpu", mpu_dev)))
-		{
-			show_base("DT0197H", "mpu", &mpu_dev->resource[0]);
-			mpu_config->io_base = mpu_dev->resource[0].start;
-		}
-	}
-	else
-		printk(KERN_ERR "sb: DT0197H panic: mpu not found\n");
-
-	printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner <twerner@intercomm.de>\n");
-
-	return(sb_dev);
-}
-
-static struct pci_dev *sb_init_als(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
-{
-	/* 
-	 * ALS100
-	 * very similar to both ones above above
-	 */
-
-	/*  @@@0001:Soundblaster.
-	 */
-
-	if((sb_dev = isapnp_find_dev(bus,
-				ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-	{
-		sb_dev->prepare(sb_dev);
+		/* Some cards ask for irq but don't need them - azummo */
+		if(sb_isapnp_list[slot].mpu_irq == -1)
+			mpu_dev[card]->irq_resource[0].flags = 0;
 		
-		if((sb_dev = activate_dev("ALS100", "sb", sb_dev)))
-		{
-			hw_config->io_base 	= sb_dev->resource[0].start;
-			hw_config->irq 		= sb_dev->irq_resource[0].start;
-			hw_config->dma 		= sb_dev->dma_resource[1].start;
-			hw_config->dma2 	= sb_dev->dma_resource[0].start;
-
-			show_base("ALS100", "sb", &sb_dev->resource[0]);
+		if((mpu_dev[card] = activate_dev(sb_isapnp_list[slot].name, "mpu", mpu_dev[card]))) {
+			mpu_config->io_base = mpu_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start;
+			if(sb_isapnp_list[slot].mpu_irq != -1)
+				mpu_config->irq = mpu_dev[card]->irq_resource[sb_isapnp_list[slot].mpu_irq].start;
 		}
-
-		if(!sb_dev) return(NULL);
 	}
 	else
-		printk(KERN_ERR "sb: ALS100 panic: sb base not found\n");
-
-	/*  @X@0001:mpu
-	 */
-
-	if((mpu_dev = isapnp_find_dev(bus,
-				ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-	{
-		mpu_dev->prepare(mpu_dev);
-
-		if((mpu_dev = activate_dev("ALS100", "mpu", mpu_dev)))
-		{
-			show_base("ALS100", "mpu", &mpu_dev->resource[0]);
-			mpu_config->io_base = mpu_dev->resource[0].start;
-		}
-	}
-	else
-		printk(KERN_ERR "sb: ALS100 panic: mpu not found\n");
-
-	printk(KERN_INFO "sb: ALS100 mail reports to Torsten Werner <twerner@intercomm.de>\n");
-
-	return(sb_dev);
+		printk(KERN_ERR "sb: %s isapnp panic: mpu not found\n", sb_isapnp_list[slot].name);
+	
+	return(sb_dev[card]);
 }
 
-#define SBF_DEV	0x01 /* Please notice that cards without this flag are on the top in the list */
-
-
-static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
-sb_isapnp_list[] __initdata = {
-	{ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0,	&sb_init_cmi,		"CMI 8330 SoundPRO" },
-	{ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0,	&sb_init_diamond,	"Diamond DT0197H" },
-	{ISAPNP_VENDOR('A','L','S'), ISAPNP_FUNCTION(0x0001), 0,	&sb_init_als,		"ALS 100" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV,	&sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV,	&sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV,	&sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV,	&sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV,	&sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV,	&sb_init_generic,	"Sound Blaster 16" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV,	&sb_init_ess,		"ESS 1688" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV,	&sb_init_ess,		"ESS 1868" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV,	&sb_init_ess,		"ESS 1868" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV,	&sb_init_ess,		"ESS 1869" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV,	&sb_init_ess,		"ESS 1878" },
-	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV,	&sb_init_ess,		"ESS 1879" },
-	{0}
-};
-
-static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
+static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, int slot, int card)
 {
-	struct pci_dev *idev = NULL;
-
-	/* You missed the init func? That's bad. */
-	if(sb_isapnp_list[slot].initfunc)
-	{
-		char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
-
-		printk(KERN_INFO "sb: %s detected\n", busname); 
+	char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
 
-		/* Initialize this baby. */
+	printk(KERN_INFO "sb: %s detected\n", busname); 
 
-		if((idev = sb_isapnp_list[slot].initfunc(bus, card, hw_config, mpu_config)))
-		{
-			/* We got it. */
+	/* Initialize this baby. */
 
-			printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",
-			       busname,
-			       hw_config->io_base, hw_config->irq, hw_config->dma,
-			       hw_config->dma2);
-			return 1;
-		}
-		else
-			printk(KERN_INFO "sb: Failed to initialize %s\n", busname);
+	if(sb_init(bus, hw_config, mpu_config, slot, card)) {
+		/* We got it. */
+		
+		printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",
+		       busname,
+		       hw_config->io_base, hw_config->irq, hw_config->dma,
+		       hw_config->dma2);
+		return 1;
 	}
 	else
-		printk(KERN_ERR "sb: Bad entry in sb_card.c PnP table\n");
+		printk(KERN_INFO "sb: Failed to initialize %s\n", busname);
 
 	return 0;
 }
 
-/* Actually this routine will detect and configure only the first card with successful
-   initialization. isapnpjump could be used to jump to a specific entry.
-   Please always add entries at the end of the array.
-   Should this be fixed? - azummo
-*/
-
-int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config) 
+int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config, int card) 
 {
+	static int first = 1;
 	int i;
 
 	/* Count entries in sb_isapnp_list */
-	for (i = 0; sb_isapnp_list[i].vendor != 0; i++);
+	for (i = 0; sb_isapnp_list[i].card_vendor != 0; i++);
+	i--;
 
 	/* Check and adjust isapnpjump */
-	if( isapnpjump < 0 || isapnpjump > ( i - 1 ) )
-	{
-		printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to 0.\n", i-1);
-		isapnpjump = 0;
+	if( isapnpjump < 0 || isapnpjump > i) {
+		isapnpjump = reverse ? i : 0;
+		printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to %d.\n", i, isapnpjump);
 	}
-	
-	for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
 
-		if(!(sb_isapnp_list[i].flags & SBF_DEV))
-		{
-			struct pci_bus *bus = NULL;
-				
-			while ((bus = isapnp_find_card(
-					sb_isapnp_list[i].vendor,
-					sb_isapnp_list[i].function,
-					bus))) {
+	if(!first || !reverse)
+		i = isapnpjump;
+	first = 0;
+	while(sb_isapnp_list[i].card_vendor != 0) {
+		static struct pci_bus *bus = NULL;
+
+		while ((bus = isapnp_find_card(
+				sb_isapnp_list[i].card_vendor,
+				sb_isapnp_list[i].card_device,
+				bus))) {
 	
-				if(sb_isapnp_init(hw_config, mpu_config, bus, NULL, i))
-					return 0;
-			}
-		}
-	}
-
-	/*  No cards found. I'll try now to search inside every card for a logical device
-	 *  that matches any entry marked with SBF_DEV in the table.
-	 */
-
-	for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
-
-		if(sb_isapnp_list[i].flags & SBF_DEV)
-		{
-			struct pci_dev *card = NULL;
-
-			while ((card = isapnp_find_dev(NULL,
-					sb_isapnp_list[i].vendor,
-					sb_isapnp_list[i].function,
-					card))) {
-
-				if(sb_isapnp_init(hw_config, mpu_config, card->bus, card, i))
-					return 0;
+			if(sb_isapnp_init(hw_config, mpu_config, bus, i, card)) {
+				isapnpjump = i; /* start next search from here */
+				return 0;
 			}
 		}
+		i += reverse ? -1 : 1;		
 	}
 
 	return -ENODEV;
@@ -566,62 +615,80 @@
 
 static int __init init_sb(void)
 {
-	printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
+	int card, max = multiple ? SB_CARDS_MAX : 1;
 
-	/* Please remember that even with CONFIG_ISAPNP defined one should still be
-		able to disable PNP support for this single driver!
-	*/
-
-#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE			
-	if(isapnp && (sb_isapnp_probe(&cfg, &cfg_mpu) < 0) ) {
-		printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
-		isapnp = 0;
-	}
+	printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
+	
+	for(card = 0; card < max; card++, sb_cards_num++) {
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+		/* Please remember that even with CONFIG_ISAPNP defined one
+		 * should still be able to disable PNP support for this 
+		 * single driver! */
+		if(isapnp && (sb_isapnp_probe(&cfg[card], &cfg_mpu[card], card) < 0) ) {
+			if(!sb_cards_num) {
+				printk(KERN_NOTICE "sb: No ISAPnP cards found, trying standard ones...\n");
+				isapnp = 0;
+			} else
+				break;
+		}
 #endif
 
-	if( isapnp == 0 ) {
-		cfg.io_base	= io;
-		cfg.irq		= irq;
-		cfg.dma		= dma;
-		cfg.dma2	= dma16;
-	}
+		if(!isapnp) {
+			cfg[card].io_base	= io;
+			cfg[card].irq		= irq;
+			cfg[card].dma		= dma;
+			cfg[card].dma2		= dma16;
+		}
 
-	cfg.card_subtype = type;
+		cfg[card].card_subtype = type;
 
-	if (!probe_sb(&cfg))
-		return -ENODEV;
-	attach_sb_card(&cfg);
+		if (!probe_sb(&cfg[card]))
+			return -ENODEV;
+		attach_sb_card(&cfg[card]);
 
-	if(cfg.slots[0]==-1)
-		return -ENODEV;
+		if(cfg[card].slots[0]==-1)
+			return -ENODEV;
 		
-	if (isapnp == 0) 
-		cfg_mpu.io_base = mpu_io;
-	if (probe_sbmpu(&cfg_mpu))
-		sbmpu = 1;
-	if (sbmpu)
-		attach_sbmpu(&cfg_mpu);
+		if (!isapnp) 
+			cfg_mpu[card].io_base = mpu_io;
+		if (probe_sbmpu(&cfg_mpu[card]))
+			sbmpu[card] = 1;
+		if (sbmpu[card])
+			attach_sbmpu(&cfg_mpu[card]);
+	}
+
+	SOUND_LOCK;
+
+	if(isapnp)
+		printk(KERN_NOTICE "sb: %d Soundblaster PnP card(s) found.\n", sb_cards_num);
+
 	return 0;
 }
 
 static void __exit cleanup_sb(void)
 {
+	int i;
+	
 	if (smw_free) {
 		vfree(smw_free);
 		smw_free = NULL;
 	}
-	unload_sb(&cfg);
-	if (sbmpu)
-		unload_sbmpu(&cfg_mpu);
-	SOUND_LOCK_END;
 
-#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE			
-	if(activated)
-	{
-		if(sb_dev) 	sb_dev->deactivate(sb_dev);
-		if(mpu_dev) 	mpu_dev->deactivate(mpu_dev);
-	}
+	for(i = 0; i < sb_cards_num; i++) {
+		unload_sb(&cfg[i], i);
+		if (sbmpu[i])
+			unload_sbmpu(&cfg_mpu[i]);
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+		if(!audio_activated[i] && sb_dev[i])
+			sb_dev[i]->deactivate(sb_dev[i]);
+		if(!mpu_activated[i] && mpu_dev[i])
+			mpu_dev[i]->deactivate(mpu_dev[i]);
+		if(!opl_activated[i] && opl_dev[i])
+			opl_dev[i]->deactivate(opl_dev[i]);
 #endif
+	}
+	SOUND_LOCK_END;	
 }
 
 module_init(init_sb);
@@ -630,7 +697,7 @@
 #ifndef MODULE
 static int __init setup_sb(char *str)
 {
-	/* io, irq, dma, dma2 */
+	/* io, irq, dma, dma2 - just the basics */
 	int ints[5];
 	
 	str = get_options(str, ARRAY_SIZE(ints), ints);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.3.99-pre5/linux/drivers/sound/sb_common.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/sb_common.c	Tue Apr 11 19:13:15 2000
@@ -1258,7 +1258,8 @@
 				return 0;
 			}
 			hw_config->name = "Sound Blaster 16";
-			hw_config->irq = -devc->irq;
+			if (hw_config->irq < 3 || hw_config->irq == devc->irq)
+				hw_config->irq = -devc->irq;
 			if (devc->minor > 12)		/* What is Vibra's version??? */
 				sb16_set_mpu_port(devc, hw_config);
 			break;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v2.3.99-pre5/linux/drivers/sound/sequencer.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/sequencer.c	Fri Apr 21 13:29:03 2000
@@ -1561,6 +1561,7 @@
 	return put_user(val, (int *)arg);
 }
 
+/* No kernel lock - we're using the global irq lock here */
 unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait)
 {
 	unsigned long flags;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.99-pre5/linux/drivers/sound/sonicvibes.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/sound/sonicvibes.c	Fri Apr 21 13:29:35 2000
@@ -1475,6 +1475,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
@@ -2069,6 +2070,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int sv_midi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.3.99-pre5/linux/drivers/sound/sound_core.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/sound_core.c	Wed Apr 12 09:47:28 2000
@@ -370,10 +370,11 @@
 
 /**
  *	unregister_sound_special - unregister a special sound device
- *	@unit: Unit number to allocate
+ *	@unit: unit number to allocate
  *
- *	Release a sound device that was allocated with register_sound_special.
- *	The unit passed is the return value from the register function.
+ *	Release a sound device that was allocated with
+ *	register_sound_special(). The unit passed is the return value from
+ *	the register function.
  */
 
 
@@ -386,9 +387,9 @@
 
 /**
  *	unregister_sound_mixer - unregister a mixer
- *	@unit: Unit number to allocate
+ *	@unit: unit number to allocate
  *
- *	Release a sound device that was allocated with register_sound_mixer.
+ *	Release a sound device that was allocated with register_sound_mixer().
  *	The unit passed is the return value from the register function.
  */
 
@@ -401,9 +402,9 @@
 
 /**
  *	unregister_sound_midi - unregister a midi device
- *	@unit: Unit number to allocate
+ *	@unit: unit number to allocate
  *
- *	Release a sound device that was allocated with register_sound_midi.
+ *	Release a sound device that was allocated with register_sound_midi().
  *	The unit passed is the return value from the register function.
  */
 
@@ -416,9 +417,9 @@
 
 /**
  *	unregister_sound_dsp - unregister a DSP device
- *	@unit: Unit number to allocate
+ *	@unit: unit number to allocate
  *
- *	Release a sound device that was allocated with register_sound_dsp.
+ *	Release a sound device that was allocated with register_sound_dsp().
  *	The unit passed is the return value from the register function.
  *
  *	Both of the allocated units are released together automatically.
@@ -434,9 +435,9 @@
 
 /**
  *	unregister_sound_synth - unregister a synth device
- *	@unit: Unit number to allocate
+ *	@unit: unit number to allocate
  *
- *	Release a sound device that was allocated with register_sound_synth.
+ *	Release a sound device that was allocated with register_sound_synth().
  *	The unit passed is the return value from the register function.
  */
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.3.99-pre5/linux/drivers/sound/soundcard.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/sound/soundcard.c	Wed Apr 12 09:47:28 2000
@@ -605,7 +605,7 @@
 
 static void destroy_special_devices(void)
 {
-	unregister_sound_special(6);
+	unregister_sound_special(1);
 	unregister_sound_special(8);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.3.99-pre5/linux/drivers/sound/trident.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/sound/trident.c	Mon Apr 24 13:39:34 2000
@@ -29,6 +29,13 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.14.2 Mar 29 2000 Ching Ling Lee
+ *	Add clear to silence advance in trident_update_ptr 
+ *	fix invalid data of the end of the sound
+ *  v0.14.1 Mar 24 2000 Ching Ling Lee
+ *	ALi 5451 support added, playback and recording O.K.
+ *	ALi 5451 originally developed and structured based on sonicvibes, and
+ *	suggested to merge into this file by Alan Cox.
  *  v0.14 Mar 15 2000 Ollie Lho
  *	5.1 channel output support with channel binding. What's the Matrix ?
  *  v0.13.1 Mar 10 2000 Ollie Lho
@@ -74,6 +81,7 @@
  *	new pci device driver interface for 2.4 kernel (done)
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/string.h>
@@ -127,13 +135,15 @@
 enum {
 	TRIDENT_4D_DX = 0,
 	TRIDENT_4D_NX,
-	SIS_7018
+	SIS_7018,
+	ALI_5451
 };
 
 static char * card_names[] = {
 	"Trident 4DWave DX",
 	"Trident 4DWave NX",
-	"SiS 7018 PCI Audio"
+	"SiS 7018 PCI Audio",
+	"ALi Audio Accelerator"
 };
 
 static struct pci_device_id trident_pci_tbl [] __initdata = {
@@ -143,6 +153,9 @@
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_NX},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018},
+	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5451,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI_5451},
+	{0,}
 };
 
 MODULE_DEVICE_TABLE (pci, trident_pci_tbl);
@@ -170,7 +183,7 @@
 		/* hardware channel */
 		struct trident_channel *channel;
 
-		/* OSS buffer manangemeent stuff */
+		/* OSS buffer management stuff */
 		void *rawbuf;
 		dma_addr_t dma_handle;
 		unsigned buforder;
@@ -194,6 +207,8 @@
 		/* OSS stuff */
 		unsigned mapped:1;
 		unsigned ready:1;
+		unsigned endcleared:1;
+		unsigned update_flag;
 		unsigned ossfragshift;
 		int ossmaxfrags;
 		unsigned subdivision;
@@ -252,6 +267,7 @@
 	/* PCI device stuff */
 	struct pci_dev * pci_dev;
 	u16 pci_id;
+	u8 revision;
 
 	/* soundcore stuff */
 	int dev_audio;
@@ -264,6 +280,12 @@
 	/* hardware resources */
 	unsigned long iobase;
 	u32 irq;
+	
+	/* Function support */
+	struct trident_channel *(*alloc_pcm_channel)(struct trident_card *);
+	struct trident_channel *(*alloc_rec_pcm_channel)(struct trident_card *);
+	void (*free_pcm_channel)(struct trident_card *, int chan);
+	void (*address_interrupt)(struct trident_card *);
 };
 
 /* table to map from CHANNELMASK to channel attribute for SiS 7018 */
@@ -281,6 +303,9 @@
 
 static struct trident_card *devs = NULL;
 
+static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
+static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg);
+
 static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
 static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg);
 
@@ -301,6 +326,7 @@
 	case PCI_DEVICE_ID_SI_7018:
 		global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN);
 		break;
+	case PCI_DEVICE_ID_ALI_5451:
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
 		global_control |= (ENDLP_IE | MIDLP_IE);
@@ -463,6 +489,46 @@
 	return NULL;
 }
 
+static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card)
+{
+	struct trident_pcm_bank *bank;
+	int idx;
+
+	bank = &card->banks[BANK_A];
+
+	if (bank->bitmap == ~0UL) {
+		/* no more free channels avaliable */
+		printk(KERN_ERR "trident: no more channels available on Bank B.\n");
+		return NULL;
+	}
+	for (idx = 0; idx <= 31; idx++) {
+		if (!(bank->bitmap & (1 << idx))) {
+			struct trident_channel *channel = &bank->channels[idx];
+			bank->bitmap |= 1 << idx;
+			channel->num = idx;
+			return channel;
+		}
+	}
+	return NULL;
+}
+
+static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card)
+{
+	struct trident_pcm_bank *bank;
+	int idx = ALI_PCM_IN_CHANNEL;
+
+	bank = &card->banks[BANK_A];
+	
+	if (!(bank->bitmap & (1 << idx))) {
+		struct trident_channel *channel = &bank->channels[idx];
+		bank->bitmap |= 1 << idx;
+		channel->num = idx;
+		return channel;
+	}
+	return NULL;
+}
+
+
 static void trident_free_pcm_channel(struct trident_card *card, int channel)
 {
 	int bank;
@@ -478,7 +544,24 @@
 	}
 }
 
+static void ali_free_pcm_channel(struct trident_card *card, int channel)
+{
+	int bank;
+
+	if (channel > 31)
+		return;
+
+	bank = channel >> 5;
+	channel = channel & 0x1f;
+
+	if (card->banks[bank].bitmap & (1 << (channel))) {
+		card->banks[bank].bitmap &= ~(1 << (channel));
+	}
+}
+
+
 /* called with spin lock held */
+
 static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel)
 {
 	int i;
@@ -491,6 +574,9 @@
 	/* output the channel registers */
 	for (i = 0; i < CHANNEL_REGS; i++) {
 		outl(data[i], TRID_REG(card, CHANNEL_START + 4*i));
+		if (i == 2)
+			if (card->pci_id == PCI_DEVICE_ID_ALI_5451)
+				i++;	//skip i=3
 	}
 
 	return TRUE;
@@ -509,6 +595,11 @@
 
 	switch (state->card->pci_id)
 	{
+	case PCI_DEVICE_ID_ALI_5451:
+		data[0] = 0; /* Current Sample Offset */
+		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+		data[3] = 0;
+		break;	
 	case PCI_DEVICE_ID_SI_7018:
 		data[0] = 0; /* Current Sample Offset */
 		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
@@ -654,6 +745,7 @@
 	/* Enable AC-97 ADC (capture) */
 	switch (card->pci_id) 
 	{
+	case PCI_DEVICE_ID_ALI_5451:
 	case PCI_DEVICE_ID_SI_7018:
 		/* for 7018, the ac97 is always in playback/record (duplex) mode */
 		break;
@@ -717,6 +809,7 @@
 
 	switch (state->card->pci_id) 
 	{
+	case PCI_DEVICE_ID_ALI_5451:
 	case PCI_DEVICE_ID_SI_7018:
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
 		/* 16 bits ESO, CSO for 7018 and DX */
@@ -1029,8 +1122,11 @@
 static void trident_update_ptr(struct trident_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned hwptr;
+	unsigned hwptr, swptr;
+	int clear_cnt = 0;
 	int diff;
+	unsigned char silence;
+	unsigned half_dmasize;
 
 	/* update hardware pointer */
 	hwptr = trident_get_dma_addr(state);
@@ -1054,6 +1150,31 @@
 				__stop_adc(state);
 				dmabuf->error++;
 			}
+			else if (!dmabuf->endcleared) {
+				swptr = dmabuf->swptr;
+				silence = (dmabuf->fmt & TRIDENT_FMT_16BIT ? 0 : 0x80);
+				if (dmabuf->update_flag & ALI_ADDRESS_INT_UPDATE) {
+					/* We must clear end data of 1/2 dmabuf if needed.
+					   According to 1/2 algorithm of Address Engine Interrupt,
+					   check the validation of the data of half dmasize. */
+					half_dmasize = dmabuf->dmasize / 2;
+					if ((diff = hwptr - half_dmasize) < 0 )
+						diff = hwptr;
+					if ((dmabuf->count + diff) < half_dmasize) {
+						//there is invalid data in the end of half buffer
+						if ((clear_cnt = half_dmasize - swptr) < 0)
+							clear_cnt += half_dmasize;
+						memset (dmabuf->rawbuf + swptr, silence, clear_cnt);	//clear the invalid data
+						dmabuf->endcleared = 1;
+					}
+				} else if (dmabuf->count < (signed) dmabuf->fragsize) {
+					clear_cnt = dmabuf->fragsize;
+					if ((swptr + clear_cnt) > dmabuf->dmasize)
+						clear_cnt = dmabuf->dmasize - swptr;
+					memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
+					dmabuf->endcleared = 1;
+				}
+			}			
 			/* since dma machine only interrupts at ESO and ESO/2, we sure have at
 			   least half of dma buffer free, so wake up the process unconditionally */
 			wake_up(&dmabuf->wait);
@@ -1080,13 +1201,54 @@
 			wake_up(&dmabuf->wait);
 		}
 	}
+	dmabuf->update_flag &= ~ALI_ADDRESS_INT_UPDATE;
 }
 
-static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void trident_address_interrupt(struct trident_card *card)
 {
+	int i;
 	struct trident_state *state;
-	struct trident_card *card = (struct trident_card *)dev_id;
+	
+	/* Update the pointers for all channels we are running. */
+	/* FIXME: should read interrupt status only once */
+	for (i = 0; i < NR_HW_CH; i++) {
+		if (trident_check_channel_interrupt(card, 63 - i)) {
+			trident_ack_channel_interrupt(card, 63 - i);
+			if ((state = card->states[i]) != NULL) {
+				trident_update_ptr(state);
+			} else {
+				printk("trident: spurious channel irq %d.\n",
+				       63 - i);
+				trident_stop_voice(card, 63 - i);
+				trident_disable_voice_irq(card, 63 - i);
+			}
+		}
+	}
+}
+
+static void ali_address_interrupt(struct trident_card *card)
+{
 	int i;
+	struct trident_state *state;
+	
+	for (i = 0; i < NR_HW_CH; i++) {
+		if (trident_check_channel_interrupt(card, i)) {
+			trident_ack_channel_interrupt(card, i);
+			if ((state = card->states[i]) != NULL) {
+				state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE;
+				trident_update_ptr(state);
+			} else {
+				printk("ali: spurious channel irq %d.\n", i);
+				trident_stop_voice(card, i);
+				trident_disable_voice_irq(card, i);
+			}
+		}
+	}
+}
+
+static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct trident_card *card = (struct trident_card *)dev_id;
 	u32 event;
 
 	spin_lock(&card->lock);
@@ -1097,21 +1259,7 @@
 #endif
 
 	if (event & ADDRESS_IRQ) {
-		/* Update the pointers for all channels we are running. */
-		/* FIXME: should read interrupt status only once */
-		for (i = 0; i < NR_HW_CH; i++) {
-			if (trident_check_channel_interrupt(card, 63 - i)) {
-				trident_ack_channel_interrupt(card, 63 - i);
-				if ((state = card->states[i]) != NULL) {
-					trident_update_ptr(state);
-				} else {
-					printk("trident: spurious channel irq %d.\n",
-					       63 - i);
-					trident_stop_voice(card, 63 - i);
-					trident_disable_voice_irq(card, 63 - i);
-				}
-			}
-		}
+		card->address_interrupt(card);
 	}
 
 	/* manually clear interrupt status, bad hardware design, blame T^2 */
@@ -1151,6 +1299,9 @@
 		return -EFAULT;
 	ret = 0;
 
+	if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)
+		outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) | ALI_PCM_IN_ENABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL));
+
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
 		if (dmabuf->count > (signed) dmabuf->dmasize) {
@@ -1250,6 +1401,10 @@
 		return -EFAULT;
 	ret = 0;
 
+	if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)
+		if (dmabuf->channel->num == ALI_PCM_IN_CHANNEL)
+			outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) & ALI_PCM_IN_DISABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL));
+
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
 		if (dmabuf->count < 0) {
@@ -1312,6 +1467,7 @@
 		spin_lock_irqsave(&state->card->lock, flags);
 		dmabuf->swptr = swptr;
 		dmabuf->count += cnt;
+		dmabuf->endcleared = 0;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		count -= cnt;
@@ -1322,6 +1478,7 @@
 	return ret;
 }
 
+/* No kernel lock - we have our own spinlock */
 static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
@@ -1733,7 +1890,12 @@
 
  found_virt:
 	/* found a free virtual channel, allocate hardware channels */
-	if ((dmabuf->channel = trident_alloc_pcm_channel(card)) == NULL) {
+	if(file->f_mode & FMODE_READ)
+		dmabuf->channel = card->alloc_rec_pcm_channel(card);
+	else
+		dmabuf->channel = card->alloc_pcm_channel(card);
+		
+	if (dmabuf->channel == NULL) {
 		kfree (card->states[i]);
 		card->states[i] = NULL;;
 		return -ENODEV;
@@ -1767,7 +1929,12 @@
 	}
 
 	if (file->f_mode & FMODE_READ) {
-		/* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample,
+		if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
+			card->states[ALI_PCM_IN_CHANNEL] = state;
+			card->states[i] = NULL;
+			state->virt = ALI_PCM_IN_CHANNEL;
+		}
+		/* FIXME: Trident 4d can only record in signed 16-bits stereo, 48kHz sample,
 		   to be dealed with in trident_set_adc_rate() ?? */
 		dmabuf->fmt &= ~TRIDENT_FMT_MASK;
 		if ((minor & 0x0f) == SND_DEV_DSP16)
@@ -1809,12 +1976,12 @@
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(state);
 		dealloc_dmabuf(state);
-		trident_free_pcm_channel(state->card, dmabuf->channel->num);
+		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
 	}
 	if (file->f_mode & FMODE_READ) {
 		stop_adc(state);
 		dealloc_dmabuf(state);
-		trident_free_pcm_channel(state->card, dmabuf->channel->num);
+		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
 	}
 
 	kfree(state->card->states[state->virt]);
@@ -1944,6 +2111,101 @@
 	return ((u16) (data >> 16));
 }
 
+/* Write AC97 codec registers for ALi*/
+static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask;
+	unsigned int wCount1 = 0xffff;
+	unsigned int wCount2= 0xffff;
+	unsigned long chk1, chk2;
+	unsigned long flags;
+	u32 data;
+
+	data = ((u32) val) << 16;
+
+	address = ALI_AC97_WRITE;
+	mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
+	if (codec->id)
+		mask |= ALI_AC97_SECONDARY;
+	if (card->revision == 0x02)
+		mask |= ALI_AC97_WRITE_MIXER_REGISTER;
+		
+	spin_lock_irqsave(&card->lock, flags);
+	while (wCount1--) {
+		if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_WRITE) == 0) {
+			data |= (mask | (reg & AC97_REG_ADDR));
+			
+			chk1 = inl(TRID_REG(card,  ALI_STIMER));
+			chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			while (wCount2-- && (chk1 == chk2))
+				chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			if (wCount2 == 0) {
+				spin_unlock_irqrestore(&card->lock, flags);
+				return;
+			}
+			outl(data, TRID_REG(card, address));	//write!
+			spin_unlock_irqrestore(&card->lock, flags);
+			return;	//success
+		}
+		inw(TRID_REG(card, address));	//wait a read cycle
+	}
+
+	printk(KERN_ERR "ali: AC97 CODEC write timed out.\n");
+	spin_unlock_irqrestore(&card->lock, flags);
+	return;
+}
+
+/* Read AC97 codec registers for ALi*/
+static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask;
+        unsigned int wCount1 = 0xffff;
+        unsigned int wCount2= 0xffff;
+        unsigned long chk1, chk2;
+	unsigned long flags;
+	u32 data;
+
+	address = ALI_AC97_READ;
+	if (card->revision == 0x02) {
+		address = ALI_AC97_WRITE;
+		mask &= ALI_AC97_READ_MIXER_REGISTER;
+	}
+	mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY;
+	if (codec->id)
+		mask |= ALI_AC97_SECONDARY;
+
+	spin_lock_irqsave(&card->lock, flags);
+	data = (mask | (reg & AC97_REG_ADDR));
+	while (wCount1--) {
+		if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) {
+			chk1 = inl(TRID_REG(card,  ALI_STIMER));
+			chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			while (wCount2-- && (chk1 == chk2))
+				chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			if (wCount2 == 0) {
+				printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
+				spin_unlock_irqrestore(&card->lock, flags);
+				return 0;
+			}
+			outl(data, TRID_REG(card, address));	//read!
+			wCount2 = 0xffff;
+			while (wCount2--) {
+				if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) {
+					data = inl(TRID_REG(card, address));
+					spin_unlock_irqrestore(&card->lock, flags);
+					return ((u16) (data >> 16));
+				}
+			}
+		}
+		inw(TRID_REG(card, address));	//wait a read cycle
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+	printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
+	return 0;
+}
+
 /* OSS /dev/mixer file operation methods */
 static int trident_open_mixdev(struct inode *inode, struct file *file)
 {
@@ -1999,6 +2261,11 @@
 	   really exist */
 	switch (card->pci_id)
 	{
+	case PCI_DEVICE_ID_ALI_5451:
+		outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL));
+		ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL)); 
+		ready_2nd &= SI_AC97_SECONDARY_READY;
+		break;
 	case PCI_DEVICE_ID_SI_7018:
 		/* disable AC97 GPIO interrupt */
 		outl(0x00, TRID_REG(card, SI_AC97_GPIO));
@@ -2032,10 +2299,16 @@
 		   in ac97_probe_codec */
 		codec->private_data = card;
 		codec->id = num_ac97;
-		/* controller specific low level AC97 access function */
-		codec->codec_read = trident_ac97_get;
-		codec->codec_write = trident_ac97_set;
 
+		if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
+			codec->codec_read = ali_ac97_get;
+			codec->codec_write = ali_ac97_set;
+		}
+		else {
+			codec->codec_read = trident_ac97_get;
+			codec->codec_write = trident_ac97_set;
+		}
+	
 		if (ac97_probe_codec(codec) == 0)
 			break;
 
@@ -2061,12 +2334,14 @@
 {
 	unsigned long iobase;
 	struct trident_card *card;
+	u8 revision;
 
 	if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) {
 		printk(KERN_ERR "trident: architecture does not support"
 		       " 30bit PCI busmaster DMA\n");
 		return -ENODEV;
 	}
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
 
 	iobase = pci_dev->resource[0].start;
 	if (check_region(iobase, 256)) {
@@ -2084,6 +2359,7 @@
 	card->iobase = iobase;
 	card->pci_dev = pci_dev;
 	card->pci_id = pci_id->device;
+	card->revision = revision;
 	card->irq = pci_dev->irq;
 	card->next = devs;
 	card->magic = TRIDENT_CARD_MAGIC;
@@ -2100,6 +2376,20 @@
 	printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
 	       card_names[pci_id->driver_data], card->iobase, card->irq);
 
+	if(card->pci_id == PCI_DEVICE_ID_ALI_5451)
+	{
+		card->alloc_pcm_channel = ali_alloc_pcm_channel;
+		card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
+		card->free_pcm_channel = ali_free_pcm_channel;
+		card->address_interrupt = ali_address_interrupt;
+	}
+	else
+	{
+		card->alloc_pcm_channel = trident_alloc_pcm_channel;
+		card->alloc_rec_pcm_channel = trident_alloc_pcm_channel;
+		card->free_pcm_channel = trident_free_pcm_channel;
+		card->address_interrupt = trident_address_interrupt;
+	}
 	/* claim our iospace and irq */
 	request_region(card->iobase, 256, card_names[pci_id->driver_data]);
 	if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ,
@@ -2111,7 +2401,7 @@
 	}
 	/* register /dev/dsp */
 	if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) {
-		printk(KERN_ERR "trident: coundn't register DSP device!\n");
+		printk(KERN_ERR "trident: couldn't register DSP device!\n");
 		release_region(iobase, 256);
 		free_irq(card->irq, card);
 		kfree(card);
@@ -2127,6 +2417,16 @@
 	}
 	outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
 
+	if (card->pci_id == PCI_DEVICE_ID_ALI_5451) 
+	{
+		/* edited by HMSEO for GT sound */
+#ifdef CONFIG_ALPHA_NAUTILUS
+		ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL);
+		trident_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN);
+#endif
+		/* edited by HMSEO for GT sound*/
+	}
+
 	pci_dev->driver_data = card;
 	pci_dev->dma_mask = TRIDENT_DMA_MASK;
 
@@ -2145,12 +2445,12 @@
 	trident_disable_loop_interrupts(card);
 
 	/* free hardware resources */
-	free_irq(card->irq, devs);
+	free_irq(card->irq, card);
 	release_region(card->iobase, 256);
 
 	/* unregister audio devices */
 	for (i = 0; i < NR_AC97; i++)
-		if (devs->ac97_codec[i] != NULL) {
+		if (card->ac97_codec[i] != NULL) {
 			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
 			kfree (card->ac97_codec[i]);
 		}
@@ -2159,8 +2459,8 @@
 	kfree(card);
 }
 
-MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho");
-MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
+MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee");
+MODULE_DESCRIPTION("Trident 4DWave/SiS 7018/ALi 5451 PCI Audio Driver");
 
 #define TRIDENT_MODULE_NAME "trident"
 
@@ -2176,7 +2476,7 @@
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
 
-	printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
+	printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451 PCI Audio, version "
 	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
 	if (!pci_register_driver(&trident_pci_driver)) {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/trident.h linux/drivers/sound/trident.h
--- v2.3.99-pre5/linux/drivers/sound/trident.h	Sun Mar 19 18:35:30 2000
+++ linux/drivers/sound/trident.h	Wed Apr 12 09:47:28 2000
@@ -32,6 +32,10 @@
 #define PCI_VENDOR_ID_SI			0x0139
 #endif
 
+#ifndef PCI_VENDOR_ID_ALI
+#define PCI_VENDOR_ID_ALI			0x10b9
+#endif
+
 #ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX
 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX	0x2000
 #endif
@@ -44,6 +48,10 @@
 #define PCI_DEVICE_ID_SI_7018		0x7018
 #endif
 
+#ifndef PCI_DEVICE_ID_ALI_5451
+#define PCI_DEVICE_ID_ALI_5451		0x5451
+#endif
+
 #ifndef FALSE
 #define FALSE 		0
 #define TRUE  		1
@@ -81,6 +89,28 @@
 	T4D_AINT_B	= 0xd8, T4D_AINTEN_B    = 0xdc
 };
 
+enum ali_op_registers {
+	ALI_GLOBAL_CONTROL	= 0xd4,
+	ALI_STIMER		= 0xc8
+};
+
+enum ali_global_control_bit {
+	ALI_PCM_IN_ENABLE	= 0x80000000,
+	ALI_PCM_IN_DISABLE	= 0x7fffffff
+};
+
+enum ali_pcm_in_channel_num {
+	ALI_PCM_IN_CHANNEL	= 31
+};
+
+enum ali_ac97_power_control_bit {
+	ALI_EAPD_POWER_DOWN	= 0x8000
+};
+
+enum ali_update_ptr_flags {
+	ALI_ADDRESS_INT_UPDATE	= 0x01
+};
+
 /* S/PDIF Operational Registers for 4D-NX */
 enum nx_spdif_registers {
 	NX_SPCTRL_SPCSO	= 0x24, NX_SPLBA = 0x28,
@@ -113,8 +143,20 @@
 	SI_SERIAL_INTF_CTRL = 0x48, SI_AC97_GPIO = 0x4c
 };
 
+enum ali_ac97_registers {
+	ALI_AC97_WRITE       = 0x40, ALI_AC97_READ = 0x44
+};
+
 /* Bit mask for operational registers */
 #define AC97_REG_ADDR      0x000000ff
+
+enum ali_ac97_bits {
+	ALI_AC97_BUSY_WRITE = 0x8000, ALI_AC97_BUSY_READ = 0x8000,
+	ALI_AC97_WRITE_ACTION = 0x8000, ALI_AC97_READ_ACTION = 0x8000,
+	ALI_AC97_AUDIO_BUSY = 0x4000, ALI_AC97_SECONDARY  = 0x0080,
+	ALI_AC97_READ_MIXER_REGISTER = 0xfeff,
+	ALI_AC97_WRITE_MIXER_REGISTER = 0x0100
+};
 
 enum sis7018_ac97_bits {
 	SI_AC97_BUSY_WRITE = 0x8000, SI_AC97_BUSY_READ = 0x8000,
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c
--- v2.3.99-pre5/linux/drivers/sound/vidc.c	Tue Mar  7 14:32:26 2000
+++ linux/drivers/sound/vidc.c	Tue Apr 25 17:38:33 2000
@@ -84,7 +84,7 @@
 static void
 vidc_mksound(unsigned int hz, unsigned int ticks)
 {
-	printk("BEEP - %d %d!\n", hz, ticks);
+//	printk("BEEP - %d %d!\n", hz, ticks);
 }
 
 static void
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c
--- v2.3.99-pre5/linux/drivers/sound/vwsnd.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/vwsnd.c	Fri Apr 21 13:30:35 2000
@@ -2409,6 +2409,7 @@
 	return ret;
 }
 
+/* No kernel lock - fine */
 static unsigned int vwsnd_audio_poll(struct file *file,
 				     struct poll_table_struct *wait)
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.99-pre5/linux/drivers/usb/Config.in	Tue Apr 11 15:09:19 2000
+++ linux/drivers/usb/Config.in	Fri Apr 21 14:03:01 2000
@@ -33,6 +33,7 @@
          bool '    USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT
          bool '    USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO
          bool '    USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA
+         bool '    USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET
       fi
       bool '    USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
    fi
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.99-pre5/linux/drivers/usb/acm.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/usb/acm.c	Fri Apr 21 14:02:49 2000
@@ -52,10 +52,6 @@
 #define DEBUG
 #include <linux/usb.h>
 
-void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
-			unsigned minor);
-void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
-
 /*
  * CMSPAR, some architectures can't have space and mark parity.
  */
@@ -261,7 +257,8 @@
 	if (urb->status)
 		dbg("nonzero write bulk status received: %d", urb->status);
 
-	queue_task(&acm->tqueue, &tq_scheduler);
+	queue_task(&acm->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
 }
 
 static void acm_softint(void *private)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.99-pre5/linux/drivers/usb/audio.c	Tue Apr 11 15:09:19 2000
+++ linux/drivers/usb/audio.c	Fri Apr 21 13:20:39 2000
@@ -2108,6 +2108,7 @@
 	return ret;
 }
 
+/* Called without the kernel lock - fine */
 static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- v2.3.99-pre5/linux/drivers/usb/dc2xx.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/usb/dc2xx.c	Tue Apr 25 17:38:33 2000
@@ -109,8 +109,8 @@
 
 struct camera_state {
 	struct usb_device	*dev;		/* USB device handle */
-	char			inEP;		/* read endpoint */
-	char			outEP;		/* write endpoint */
+	int			inEP;		/* read endpoint */
+	int			outEP;		/* write endpoint */
 	const struct camera	*info;		/* DC-240, etc */
 	int			subminor;	/* which minor dev #? */
 	int			isActive;	/* I/O taking place? */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/devices.c linux/drivers/usb/devices.c
--- v2.3.99-pre5/linux/drivers/usb/devices.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/devices.c	Wed Apr 26 15:22:55 2000
@@ -54,6 +54,7 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/usb.h>
+#include <linux/smp_lock.h>
 #include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
 
@@ -452,11 +453,13 @@
 	return ret;
 }
 
+/* Kernel lock for "lastev" protection */
 static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct usb_device_status *st = (struct usb_device_status *)file->private_data;
 	unsigned int mask = 0;
-	
+
+	lock_kernel();
 	if (!st) {
 		st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
 		if (!st)
@@ -475,6 +478,7 @@
 	if (st->lastev != conndiscevcnt)
 		mask |= POLLIN;
 	st->lastev = conndiscevcnt;
+	unlock_kernel();
 	return mask;
 }
 
@@ -494,7 +498,7 @@
         return 0;
 }
 
-static long long usb_device_lseek(struct file * file, long long offset, int orig)
+static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
 {
 	switch (orig) {
 	case 0:
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
--- v2.3.99-pre5/linux/drivers/usb/devio.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/devio.c	Wed Apr 26 15:22:55 2000
@@ -162,7 +162,7 @@
 	return ret;
 }
 
-static long long usbdev_lseek(struct file *file, long long offset, int orig)
+static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
 	switch (orig) {
 	case 0:
@@ -989,6 +989,7 @@
 	return ret;
 }
 
+/* No kernel lock - fine */
 static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct dev_state *ps = (struct dev_state *)file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/drivers.c linux/drivers/usb/drivers.c
--- v2.3.99-pre5/linux/drivers/usb/drivers.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/drivers.c	Wed Apr 26 15:22:55 2000
@@ -94,7 +94,7 @@
 	return ret;
 }
 
-static long long usb_driver_lseek(struct file * file, long long offset, int orig)
+static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig)
 {
 	switch (orig) {
 	case 0:
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c
--- v2.3.99-pre5/linux/drivers/usb/dsbr100.c	Sun Mar 19 18:35:30 2000
+++ linux/drivers/usb/dsbr100.c	Mon Apr 24 16:20:52 2000
@@ -15,7 +15,7 @@
  You might find some interesting stuff about this module at
  http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
 
- Copyright (c) 2000 Markus Demleitner
+ Copyright (c) 2000 Markus Demleitner <msdemlei@tucana.harvard.edu>
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
@@ -33,9 +33,12 @@
 
  History:
 
+ Version 0.22:
+ 	Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, 
+	thanks to Mike Cox for pointing the problem out.
+
  Version 0.21:
- 	Markus Demleitner <msdemlei@tucana.harvard.edu>:
-	Minor cleanup, warnings if something goes wrong, lame attempt
+ 	Markus: Minor cleanup, warnings if something goes wrong, lame attempt
 	to adhere to Documentation/CodingStyle
 
  Version 0.2: 
@@ -212,13 +215,14 @@
 				return -EFAULT;
 			if(v.tuner)	/* Only 1 tuner */ 
 				return -EINVAL;
-			v.rangelow=(87*16000);
-			v.rangehigh=(108*16000);
-			/*v.flags=VIDEO_TUNER_LOW;*/
-			v.mode=VIDEO_MODE_AUTO;
-			v.signal=radio->stereo;
-			v.flags|=VIDEO_TUNER_STEREO_ON;
-			strcpy(v.name, "FM");
+			v.rangelow = 87*16;
+			v.rangehigh = 108*16;
+			v.flags = VIDEO_TUNER_LOW;
+			v.mode = VIDEO_MODE_AUTO;
+			v.signal = radio->stereo*0x7000;
+				/* Don't know how to get signal strength */
+			v.flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
+			strcpy(v.name, "DSB R-100");
 			if(copy_to_user(arg,&v, sizeof(v)))
 				return -EFAULT;
 			return 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/evdev.c linux/drivers/usb/evdev.c
--- v2.3.99-pre5/linux/drivers/usb/evdev.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/evdev.c	Fri Apr 21 13:22:23 2000
@@ -192,6 +192,7 @@
 	return retval;	
 }
 
+/* No kernel lock - fine */
 static unsigned int evdev_poll(struct file *file, poll_table *wait)
 {
 	struct evdev_list *list = file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/joydev.c linux/drivers/usb/joydev.c
--- v2.3.99-pre5/linux/drivers/usb/joydev.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/joydev.c	Fri Apr 21 13:22:42 2000
@@ -308,6 +308,7 @@
 	return retval;
 }
 
+/* No kernel lock - fine */
 static unsigned int joydev_poll(struct file *file, poll_table *wait)
 {
 	struct joydev_list *list = file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c
--- v2.3.99-pre5/linux/drivers/usb/keybdev.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/keybdev.c	Wed Apr 26 14:53:39 2000
@@ -36,7 +36,7 @@
 #include <linux/module.h>
 #include <linux/kbd_kern.h>
 
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__)
 
 static int x86_sysrq_alt = 0;
 
@@ -102,7 +102,7 @@
 	 76,125, 75,105,124,  0,115, 62,116, 59, 60,119, 61,121,114,117,
 	  0,  0,  0,  0,127, 81,  0,113,  0,  0,  0,  0,  0, 55, 55 };
 
-static int emulate_raw(unsigned int code, unsigned char upflag)
+static int emulate_raw(unsigned int keycode, int down)
 {
 	if (keycode > 127 || !mac_keycodes[keycode])
 		return -1;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
--- v2.3.99-pre5/linux/drivers/usb/mdc800.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/mdc800.c	Tue Apr 25 17:38:33 2000
@@ -30,6 +30,12 @@
  *
  * The driver supports only one camera.
  *
+ * version 0.7.3
+ * bugfix : The mdc800->state field gets set to READY after the
+ * the diconnect function sets it to NOT_CONNECTED. This makes the
+ * driver running like the camera is connected and causes some
+ * hang ups.
+ *
  * version 0.7.1
  * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
  * problems when compiled as Module.
@@ -73,20 +79,20 @@
 
 #include <linux/usb.h>
 
-#define VERSION 		"0.7.1"
-#define RELEASE_DATE "(26/03/2000)"
+#define VERSION 	"0.7.3"
+#define RELEASE_DATE 	"(24/04/2000)"
 
 /* Vendor and Product Information */
 #define MDC800_VENDOR_ID 	0x055f
 #define MDC800_PRODUCT_ID	0xa800
 
 /* Timeouts (msec) */
-#define TO_READ_FROM_IRQ 		4000
-#define TO_GET_READY				2000
-#define TO_DOWNLOAD_GET_READY	1500
-#define TO_DOWNLOAD_GET_BUSY	1500
-#define TO_WRITE_GET_READY		3000
+#define TO_DOWNLOAD_GET_READY		1500
+#define TO_DOWNLOAD_GET_BUSY		1500
+#define TO_WRITE_GET_READY		1000
 #define TO_DEFAULT_COMMAND		5000
+#define TO_READ_FROM_IRQ 		TO_DEFAULT_COMMAND
+#define TO_GET_READY			TO_DEFAULT_COMMAND
 
 /* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
 #define MDC800_DEVICE_MINOR_BASE 32
@@ -114,7 +120,7 @@
 	wait_queue_head_t	irq_wait;
 	char*			irq_urb_buffer;
 
-	int			camera_busy;		 // is camera busy ?
+	int			camera_busy;          // is camera busy ?
 	int 			camera_request_ready; // Status to synchronize with irq
 	char 			camera_response [8];	 // last Bytes send after busy
 
@@ -130,9 +136,9 @@
 
 
 	/* Device Data */
-	char			out [64];		// Answer Buffer
+	char			out [64];	// Answer Buffer
 	int 			out_ptr;		// Index to the first not readen byte
-	int			out_count;		// Bytes in the buffer
+	int			out_count;	// Bytes in the buffer
 
 	int			open;			// Camera device open ?
 	int			rw_lock;		// Block read <-> write
@@ -284,9 +290,17 @@
 	{
 		mdc800->camera_request_ready=0;
 		err ("timeout waiting for camera.");
-		return 0;
+		return -1;
 	}
-	return 1;
+	
+	if (mdc800->state == NOT_CONNECTED)
+	{
+		warn ("Camera gets disconnected during waiting for irq.");
+		mdc800->camera_request_ready=0;
+		return -2;
+	}
+	
+	return 0;
 }
 
 
@@ -301,7 +315,10 @@
 	{
 		err ("writing command fails (status=%i)", urb->status);
 	}
-	mdc800->state=READY;
+	else
+	{	
+		mdc800->state=READY;
+	}
 	wake_up_interruptible (&mdc800->write_wait);
 }
 
@@ -328,7 +345,6 @@
 	else
 	{
 		err ("request bytes fails (status:%i)", urb->status);
-		mdc800->state=READY;
 	}
 	wake_up_interruptible (&mdc800->download_wait);
 }
@@ -351,17 +367,18 @@
 
 	dbg ("(mdc800_usb_probe) called.");
 
-	if (mdc800->dev != 0)
-	{
-		warn ("only one Mustek MDC800 is supported.");
-		return 0;
-	}
 
 	if (dev->descriptor.idVendor != MDC800_VENDOR_ID)
 		return 0;
 	if (dev->descriptor.idProduct != MDC800_PRODUCT_ID)
 		return 0;
 
+	if (mdc800->dev != 0)
+	{
+		warn ("only one Mustek MDC800 is supported.");
+		return 0;
+	}
+
 	if (dev->descriptor.bNumConfigurations != 1)
 	{
 		err ("probe fails -> wrong Number of Configuration");
@@ -416,6 +433,8 @@
 
 	mdc800->dev=dev;
 	mdc800->state=READY;
+	mdc800->open=0;
+	mdc800->rw_lock=0;
 
 	/* Setup URB Structs */
 	FILL_INT_URB (
@@ -464,10 +483,8 @@
 
 	if (mdc800->state == NOT_CONNECTED)
 		return;
-
+	
 	mdc800->state=NOT_CONNECTED;
-	mdc800->open=0;
-	mdc800->rw_lock=0;
 
 	usb_unlink_urb (mdc800->irq_urb);
 	usb_unlink_urb (mdc800->write_urb);
@@ -599,6 +616,12 @@
 	if (mdc800->state == NOT_CONNECTED)
 		return -EBUSY;
 
+	if (mdc800->state == WORKING)
+	{
+		warn ("Illegal State \"working\" reached during read ?!");
+		return -EBUSY;
+	}
+
 	if (!mdc800->open || mdc800->rw_lock)
 		return -EBUSY;
 	mdc800->rw_lock=1;
@@ -624,15 +647,13 @@
 				if (usb_submit_urb (mdc800->download_urb))
 				{
 					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
-					mdc800->state=READY;
 					mdc800->rw_lock=0;
 					return len-left;
 				}
 				interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000);
 				if (mdc800->download_urb->status != 0)
 				{
-					err ("requesting bytes fails (status=%i)",mdc800->download_urb->status);
-					mdc800->state=READY;
+					err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
 					mdc800->rw_lock=0;
 					return len-left;
 				}
@@ -710,7 +731,12 @@
 		{
 			int answersize;
 
-			mdc800_usb_waitForIRQ (0,TO_GET_READY);
+			if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
+			{
+				err ("Camera didn't get ready.\n");
+				mdc800->rw_lock=0;
+				return -EIO;
+			}
 
 			answersize=mdc800_getAnswerSize (mdc800->in[1]);
 
@@ -720,14 +746,12 @@
 			{
 				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
 				mdc800->rw_lock=0;
-				mdc800->state=READY;
 				return -EIO;
 			}
-			interruptible_sleep_on_timeout (&mdc800->write_wait, TO_DEFAULT_COMMAND*HZ/1000);
+			interruptible_sleep_on_timeout (&mdc800->write_wait, TO_WRITE_GET_READY*HZ/1000);
 			if (mdc800->state == WORKING)
 			{
 				usb_unlink_urb (mdc800->write_urb);
-				mdc800->state=READY;
 				mdc800->rw_lock=0;
 				return -EIO;
 			}
@@ -756,10 +780,9 @@
 					if (answersize)
 					{
 
-						if (!mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
+						if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
 						{
 							err ("requesting answer from irq fails");
-							mdc800->state=READY;
 							mdc800->rw_lock=0;
 							return -EIO;
 						}
@@ -785,11 +808,10 @@
 					}
 					else
 					{
-						if (!mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
+						if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
 						{
 							err ("Command Timeout.");
 							mdc800->rw_lock=0;
-							mdc800->state=READY;
 							return -EIO;
 						}
 					}
@@ -811,21 +833,10 @@
 /* File Operations of this drivers */
 static struct file_operations mdc800_device_ops =
 {
-	0,					/* llseek */
-	mdc800_device_read,
-	mdc800_device_write,
-	0,					/* readdir */
-	0,					/* poll */
-	0,					/* ioctl, this can be used to detect USB ! */
-	0,					/* mmap */
-	mdc800_device_open,
-	0,					/* flush */
-	mdc800_device_release,
-	0,					/* async */
-	0,					/* fasync */
-	0,					/* check_media_change */
-//	0,					/* revalidate */
-//	0					/* lock */
+	read:		mdc800_device_read,
+	write:		mdc800_device_write,
+	open:		mdc800_device_open,
+	release:	mdc800_device_release,
 };
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c
--- v2.3.99-pre5/linux/drivers/usb/mousedev.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/mousedev.c	Fri Apr 21 13:22:59 2000
@@ -39,11 +39,11 @@
 #include <linux/input.h>
 #include <linux/config.h>
 
-#ifndef CONFIG_MOUSEDEV_SCREEN_X
-#define CONFIG_MOUSEDEV_SCREEN_X	1024
+#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
+#define CONFIG_INPUT_MOUSEDEV_SCREEN_X	1024
 #endif
-#ifndef CONFIG_MOUSEDEV_SCREEN_Y
-#define CONFIG_MOUSEDEV_SCREEN_Y	768
+#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
+#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y	768
 #endif
 
 struct mousedev {
@@ -93,12 +93,12 @@
 					switch (code) {
 						case ABS_X:	
 							size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-							list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
+							list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size;
 							list->oldx += list->dx * size;
 							break;
 						case ABS_Y:
 							size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-							list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+							list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size;
 							list->oldy -= list->dy * size;
 							break;
 					}
@@ -365,6 +365,7 @@
 	return count;	
 }
 
+/* No kernel lock - fine */
 static unsigned int mousedev_poll(struct file *file, poll_table *wait)
 {
 	struct mousedev_list *list = file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.99-pre5/linux/drivers/usb/printer.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/printer.c	Fri Apr 21 13:23:13 2000
@@ -198,6 +198,7 @@
 	return 0;
 }
 
+/* No kernel lock - fine */
 static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct usblp *usblp = file->private_data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/rio500.c linux/drivers/usb/rio500.c
--- v2.3.99-pre5/linux/drivers/usb/rio500.c	Fri Mar 10 16:40:45 2000
+++ linux/drivers/usb/rio500.c	Mon Apr 24 16:15:01 2000
@@ -44,7 +44,7 @@
 /* stall/wait timeout for rio */
 #define NAK_TIMEOUT (HZ)
 
-#define IBUF_SIZE 128
+#define IBUF_SIZE 0x1000
 
 /* Size of the rio buffer */
 #define OBUF_SIZE 0x10000
@@ -317,7 +317,7 @@
 		result = usb_bulk_msg(rio->rio_dev,
 				      usb_rcvbulkpipe(rio->rio_dev, 1),
 				      ibuf, this_read, &partial,
-				      (int) (HZ * .1));
+				      (int) (HZ * 8));
 
 		dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
 		       result, this_read, partial);
@@ -405,18 +405,11 @@
 
 static struct
 file_operations usb_rio_fops = {
-	NULL,			/* seek */
-	read_rio,
-	write_rio,
-	NULL,			/* readdir */
-	NULL,			/* poll */
-	ioctl_rio,		/* ioctl */
-	NULL,			/* mmap */
-	open_rio,
-	NULL,			/* flush */
-	close_rio,
-	NULL,
-	NULL,			/* fasync */
+	read:		read_rio,
+	write:		write_rio,
+	ioctl:		ioctl_rio,
+	open:		open_rio,
+	release:	close_rio,
 };
 
 static struct
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- v2.3.99-pre5/linux/drivers/usb/serial/Makefile	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/Makefile	Fri Apr 21 14:03:01 2000
@@ -4,7 +4,7 @@
 
 O_TARGET	:= usb-serial.o
 M_OBJS		:= usb-serial.o
-O_OBJS		:= usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o
+O_OBJS		:= usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o
 MOD_LIST_NAME	:= USB_SERIAL_MODULES
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.3.99-pre5/linux/drivers/usb/serial/ftdi_sio.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/ftdi_sio.c	Thu Apr 13 08:59:54 2000
@@ -153,7 +153,7 @@
 /* do some startup allocations not currently performed by usb_serial_probe() */
 static int ftdi_sio_startup (struct usb_serial *serial)
 {
-	init_waitqueue_head(&serial->write_wait);
+	init_waitqueue_head(&serial->port[0].write_wait);
 	
 	return (0);
 }
@@ -291,7 +291,7 @@
 		/* Was seeing a race here, got a read callback, then write callback before
 		   hitting interuptible_sleep_on  - so wrapping in add_wait_queue stuff */
 
-		add_wait_queue(&serial->write_wait, &wait);
+		add_wait_queue(&port->write_wait, &wait);
 		set_current_state (TASK_INTERRUPTIBLE);
 		while (port->write_urb->status == -EINPROGRESS) {
 			dbg("ftdi_sio - write in progress - retrying");
@@ -301,13 +301,13 @@
 			}
 			if (signal_pending(current)) {
 				current->state = TASK_RUNNING;
-				remove_wait_queue(&serial->write_wait, &wait);				
+				remove_wait_queue(&port->write_wait, &wait);
 				rc = -ERESTARTSYS;
 				goto err;
 			}
 			schedule();
 		}		
-		remove_wait_queue(&serial->write_wait, &wait);
+		remove_wait_queue(&port->write_wait, &wait);
 		set_current_state(TASK_RUNNING);
 
 		count += data_offset;
@@ -388,7 +388,7 @@
 		return;
 	}
 
-	wake_up_interruptible(&serial->write_wait);
+	wake_up_interruptible(&port->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
 		(tty->ldisc.write_wakeup)(tty);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c
--- v2.3.99-pre5/linux/drivers/usb/serial/keyspan_pda.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/keyspan_pda.c	Thu Apr 13 08:59:54 2000
@@ -52,78 +52,20 @@
 
 #include "usb-serial.h"
 
+struct keyspan_pda_private {
+	int			tx_room;
+	int			tx_throttled;
+};
+
 #define KEYSPAN_VENDOR_ID		0x06cd
 #define KEYSPAN_PDA_FAKE_ID		0x0103
 #define KEYSPAN_PDA_ID			0x0104 /* no clue */
 
-/* function prototypes for a Keyspan PDA serial converter */
-static int  keyspan_pda_open		(struct usb_serial_port *port,
-					 struct file *filp);
-static void keyspan_pda_close		(struct usb_serial_port *port,
-					 struct file *filp);
-static int  keyspan_pda_startup		(struct usb_serial *serial);
-static void keyspan_pda_rx_throttle	(struct usb_serial_port *port);
-static void keyspan_pda_rx_unthrottle	(struct usb_serial_port *port);
-static int  keyspan_pda_setbaud		(struct usb_serial *serial, int baud);
-static int  keyspan_pda_write_room	(struct usb_serial_port *port);
-static int  keyspan_pda_write		(struct usb_serial_port *port,
-					 int from_user,
-					 const unsigned char *buf,
-					 int count);
-static void keyspan_pda_write_bulk_callback (struct urb *urb);
-static int  keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
-static int  keyspan_pda_ioctl		(struct usb_serial_port *port,
-					 struct file *file,
-					 unsigned int cmd,
-					 unsigned long arg);
-static void keyspan_pda_set_termios	(struct usb_serial_port *port,
-					 struct termios *old);
-static void keyspan_pda_break_ctl	(struct usb_serial_port *port,
-					 int break_state);
-static int  keyspan_pda_fake_startup	(struct usb_serial *serial);
-
-
 /* All of the device info needed for the Keyspan PDA serial converter */
 static __u16	keyspan_vendor_id		= KEYSPAN_VENDOR_ID;
 static __u16	keyspan_pda_fake_product_id	= KEYSPAN_PDA_FAKE_ID;
 static __u16	keyspan_pda_product_id		= KEYSPAN_PDA_ID;
-struct usb_serial_device_type keyspan_pda_fake_device = {
-	name:			"Keyspan PDA - (prerenumeration)",
-	idVendor:		&keyspan_vendor_id,		/* the Keyspan PDA vendor ID */
-	idProduct:		&keyspan_pda_fake_product_id,	/* the Keyspan PDA initial product id */
-	needs_interrupt_in:	DONT_CARE,			/* don't have to have an interrupt in endpoint */
-	needs_bulk_in:		DONT_CARE,			/* don't have to have a bulk in endpoint */
-	needs_bulk_out:		DONT_CARE,			/* don't have to have a bulk out endpoint */
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_pda_fake_startup
-};
-struct usb_serial_device_type keyspan_pda_device = {
-	name:			"Keyspan PDA",
-	idVendor:		&keyspan_vendor_id,		/* the Keyspan PDA vendor ID */
-	idProduct:		&keyspan_pda_product_id,	/* the Keyspan PDA product id */
-	needs_interrupt_in:	MUST_HAVE,
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	1,
-	num_bulk_in:		0,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			keyspan_pda_open,
-	close:			keyspan_pda_close,
-	write:			keyspan_pda_write,
-	write_room:		keyspan_pda_write_room,
-	write_bulk_callback: 	keyspan_pda_write_bulk_callback,
-	chars_in_buffer:	keyspan_pda_chars_in_buffer,
-	throttle:		keyspan_pda_rx_throttle,
-	unthrottle:		keyspan_pda_rx_unthrottle,
-	startup:		keyspan_pda_startup,
-	ioctl:			keyspan_pda_ioctl,
-	set_termios:		keyspan_pda_set_termios,
-	break_ctl:		keyspan_pda_break_ctl,
-};
+
 
 
 static void keyspan_pda_rx_interrupt (struct urb *urb)
@@ -133,6 +75,8 @@
        	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	int i;
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
 
 	/* the urb might have been killed. */
 	if (urb->status)
@@ -167,8 +111,8 @@
 			break;
 		case 2: /* tx unthrottle interrupt */
 			tty = serial->port[0].tty;
-			serial->tx_throttled = 0;
-			wake_up(&serial->write_wait); /* wake up writer */
+			priv->tx_throttled = 0;
+			wake_up(&port->write_wait); /* wake up writer */
 			wake_up(&tty->write_wait); /* them too */
 			break;
 		default:
@@ -193,7 +137,7 @@
 	   upon the device too. */
 
 	dbg("keyspan_pda_rx_throttle port %d", port->number);
-	usb_unlink_urb(port->read_urb);
+	usb_unlink_urb(port->interrupt_in_urb);
 }
 
 
@@ -201,7 +145,7 @@
 {
 	/* just restart the receive interrupt URB */
 	dbg("keyspan_pda_rx_unthrottle port %d", port->number);
-	if (usb_submit_urb(port->read_urb))
+	if (usb_submit_urb(port->interrupt_in_urb))
 		dbg(" usb_submit_urb(read urb) failed");
 	return;
 }
@@ -409,8 +353,10 @@
 	struct usb_serial *serial = port->serial;
 	int request_unthrottle = 0;
 	int rc = 0;
+	struct keyspan_pda_private *priv;
 	DECLARE_WAITQUEUE(wait, current);
 
+	priv = (struct keyspan_pda_private *)(port->private);
 	/* guess how much room is left in the device's ring buffer, and if we
 	   want to send more than that, check first, updating our notion of
 	   what is left. If our write will result in no room left, ask the
@@ -419,7 +365,7 @@
 	   select() or poll() too) until we receive that unthrottle interrupt.
 	   Block if we can't write anything at all, otherwise write as much as
 	   we can. */
-
+	dbg("keyspan_pda_write(%d)",count);
 	if (count == 0) {
 		dbg(" write request of 0 bytes");
 		return (0);
@@ -434,7 +380,7 @@
 			rc = -EAGAIN;
 			goto err;
 		}
-		interruptible_sleep_on(&serial->write_wait);
+		interruptible_sleep_on(&port->write_wait);
 		if (signal_pending(current)) {
 			rc = -ERESTARTSYS;
 			goto err;
@@ -451,16 +397,16 @@
 	   have to be careful to avoid a race that would cause us to sleep
 	   forever. */
 
-	add_wait_queue(&serial->write_wait, &wait);
+	add_wait_queue(&port->write_wait, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
-	while (serial->tx_throttled) {
+	while (priv->tx_throttled) {
 		/* device can't accomodate any more characters. Sleep until it
 		   can. Woken up by an Rx interrupt message, which clears
 		   tx_throttled first. */
 		dbg(" tx_throttled, going to sleep");
 		if (signal_pending(current)) {
 			current->state = TASK_RUNNING;
-			remove_wait_queue(&serial->write_wait, &wait);
+			remove_wait_queue(&port->write_wait, &wait);
 			dbg(" woke up because of signal");
 			rc = -ERESTARTSYS;
 			goto err;
@@ -468,11 +414,11 @@
 		schedule();
 		dbg(" woke up");
 	}
-	remove_wait_queue(&serial->write_wait, &wait);
+	remove_wait_queue(&port->write_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
 	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-	if (count > serial->tx_room) {
+	if (count > priv->tx_room) {
 		unsigned char room;
 		/* Looks like we might overrun the Tx buffer. Ask the device
 		   how much room it really has */
@@ -495,15 +441,15 @@
 			return -EIO; /* device didn't return any data */
 		}
 		dbg(" roomquery says %d", room);
-		serial->tx_room = room;
-		if (count > serial->tx_room) {
+		priv->tx_room = room;
+		if (count > priv->tx_room) {
 			/* we're about to completely fill the Tx buffer, so
 			   we'll be throttled afterwards. */
-			count = serial->tx_room;
+			count = priv->tx_room;
 			request_unthrottle = 1;
 		}
 	}
-	serial->tx_room -= count;
+	priv->tx_room -= count;
 
 	if (count) {
 		/* now transfer data */
@@ -529,7 +475,7 @@
 		dbg(" request_unthrottle");
 		/* ask the device to tell us when the tx buffer becomes
 		   sufficiently empty */
-		serial->tx_throttled = 1; /* block writers */
+		priv->tx_throttled = 1; /* block writers */
 		rc = usb_control_msg(serial->dev, 
 				     usb_sndctrlpipe(serial->dev, 0),
 				     7, /* request_unthrottle */
@@ -563,7 +509,7 @@
 		return;
 	}
 	
-	wake_up_interruptible(&serial->write_wait);
+	wake_up_interruptible(&port->write_wait);
 
 	tty = port->tty;
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
@@ -576,23 +522,25 @@
 
 static int keyspan_pda_write_room (struct usb_serial_port *port)
 {
-	struct usb_serial *serial = port->serial;
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
 
 	/* used by n_tty.c for processing of tabs and such. Giving it our
 	   conservative guess is probably good enough, but needs testing by
 	   running a console through the device. */
 
-	return (serial->tx_room);
+	return (priv->tx_room);
 }
 
 
 static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
 {
-	struct usb_serial *serial = port->serial;
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
 	
 	/* when throttled, return at least WAKEUP_CHARS to tell select() (via
 	   n_tty.c:normal_poll() ) that we're not writeable. */
-	if (serial->tx_throttled)
+	if (priv->tx_throttled)
 		return 256;
 	return 0;
 }
@@ -603,6 +551,8 @@
 	struct usb_serial *serial = port->serial;
 	unsigned char room;
 	int rc;
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
 
 	if (port->active) {
 		return -EINVAL;
@@ -627,8 +577,8 @@
 		dbg(" roomquery returned 0 bytes");
 		return -EIO; /* device didn't return any data */
 	}
-	serial->tx_room = room;
-	serial->tx_throttled = room ? 0 : 1;
+	priv->tx_room = room;
+	priv->tx_throttled = room ? 0 : 1;
 
 	/* the normal serial device seems to always turn on DTR and RTS here,
 	   so do the same */
@@ -638,7 +588,7 @@
 		keyspan_pda_set_modem_info(serial, 0);
 
 	/*Start reading from the device*/
-	if (usb_submit_urb(port->read_urb))
+	if (usb_submit_urb(port->interrupt_in_urb))
 		dbg(" usb_submit_urb(read int) failed");
 
 	return (0);
@@ -655,7 +605,7 @@
 
 	/* shutdown our bulk reads and writes */
 	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
+	usb_unlink_urb (port->interrupt_in_urb);
 	port->active = 0;
 }
 
@@ -691,27 +641,63 @@
 	return (1);
 }
 
-
-/* do some startup allocations not currently performed by usb_serial_probe() */
 static int keyspan_pda_startup (struct usb_serial *serial)
 {
-	struct usb_endpoint_descriptor *intin;
-	intin = serial->port[0].interrupt_in_endpoint;
+	/* allocate the private data structures for all ports. Well, for all
+	   one ports. */
 
-	/* set up the receive interrupt urb */
-	FILL_INT_URB(serial->port[0].read_urb, serial->dev,
-		     usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
-		     serial->port[0].interrupt_in_buffer,
-		     intin->wMaxPacketSize,
-		     keyspan_pda_rx_interrupt,
-		     serial,
-		     intin->bInterval);
-
-	init_waitqueue_head(&serial->write_wait);
-	
+	serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private),
+					   GFP_KERNEL);
+	if (!serial->port[0].private)
+		return (1); /* error */
+	init_waitqueue_head(&serial->port[0].write_wait);
 	return (0);
 }
 
-#endif	/* CONFIG_USB_SERIAL_KEYSPAN_PDA */
+static void keyspan_pda_shutdown (struct usb_serial *serial)
+{
+	kfree(serial->port[0].private);
+}
 
+struct usb_serial_device_type keyspan_pda_fake_device = {
+	name:			"Keyspan PDA - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_pda_fake_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		keyspan_pda_fake_startup,
+};
 
+struct usb_serial_device_type keyspan_pda_device = {
+	name:			"Keyspan PDA",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_pda_product_id,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		0,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			keyspan_pda_open,
+	close:			keyspan_pda_close,
+	write:			keyspan_pda_write,
+	write_room:		keyspan_pda_write_room,
+	write_bulk_callback: 	keyspan_pda_write_bulk_callback,
+	read_int_callback:	keyspan_pda_rx_interrupt,
+	chars_in_buffer:	keyspan_pda_chars_in_buffer,
+	throttle:		keyspan_pda_rx_throttle,
+	unthrottle:		keyspan_pda_rx_unthrottle,
+	ioctl:			keyspan_pda_ioctl,
+	set_termios:		keyspan_pda_set_termios,
+	break_ctl:		keyspan_pda_break_ctl,
+	startup:		keyspan_pda_startup,
+	shutdown:		keyspan_pda_shutdown,
+};
+
+#endif	/* CONFIG_USB_SERIAL_KEYSPAN_PDA */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- v2.3.99-pre5/linux/drivers/usb/serial/omninet.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/omninet.c	Fri Apr 21 14:03:01 2000
@@ -0,0 +1,339 @@
+/*
+ * USB ZyXEL omni.net LCD PLUS driver
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_OMNINET
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) )
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+
+#define ZYXEL_VENDOR_ID		0x0586
+#define ZYXEL_OMNINET_ID	0x1000
+
+/* function prototypes */
+static int  omninet_open		(struct usb_serial_port *port, struct file *filp);
+static void omninet_close		(struct usb_serial_port *port, struct file *filp);
+static void omninet_read_bulk_callback	(struct urb *urb);
+static void omninet_write_bulk_callback	(struct urb *urb);
+static int  omninet_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  omninet_write_room		(struct usb_serial_port *port);
+
+/* All of the device info needed for the omni.net */
+static __u16	zyxel_vendor_id			= ZYXEL_VENDOR_ID;
+static __u16	zyxel_omninet_product_id	= ZYXEL_OMNINET_ID;
+
+struct usb_serial_device_type zyxel_omninet_device = {
+	name:			"ZyXEL - omni.net lcd plus usb",
+	idVendor:		&zyxel_vendor_id,
+	idProduct:		&zyxel_omninet_product_id,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		2,
+	num_ports:		1,
+	open:			omninet_open,
+	close:			omninet_close,
+	write:			omninet_write,
+	write_room:		omninet_write_room,
+	read_bulk_callback:	omninet_read_bulk_callback,
+	write_bulk_callback:	omninet_write_bulk_callback,
+};
+
+
+/* The protocol.
+ *
+ * The omni.net always exchange 64 bytes of data with the host. The first
+ * four bytes are the control header, you can see it in the above structure.
+ *
+ * oh_seq is a sequence number. Don't know if/how it's used.
+ * oh_len is the length of the data bytes in the packet.
+ * oh_xxx Bit-mapped, related to handshaking and status info.
+ *	I normally set it to 0x03 in trasmitted frames.
+ *	7: Active when the TA is in a CONNECTed state.
+ *	6: unknown
+ *	5: handshaking, unknown
+ *	4: handshaking, unknown
+ *	3: unknown, usually 0
+ *	2: unknown, usually 0
+ *	1: handshaking, unknown, usually set to 1 in trasmitted frames
+ *	0: handshaking, unknown, usually set to 1 in trasmitted frames
+ * oh_pad Probably a pad byte.
+ *
+ * After the header you will find data bytes if oh_len was greater than zero.
+ *
+ */
+
+struct omninet_header
+{
+	__u8	oh_seq;
+	__u8	oh_len;
+	__u8	oh_xxx;
+	__u8	oh_pad;
+};
+
+struct omninet_data
+{
+	__u8	od_outseq;	// Sequence number for bulk_out URBs
+};
+
+static int omninet_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial 	*serial = port->serial;
+	struct usb_serial_port 	*wport	= &serial->port[1];
+	struct omninet_data 	*od;
+
+	dbg("omninet_open port %d", port->number);
+
+	if (port->active) {
+		dbg ("device already open");
+		return -EINVAL;
+	}
+	port->active = 1;
+
+	od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+
+	if( !od )
+	{
+		err("omninet_open: kmalloc(%d) failed.", sizeof(struct omninet_data));
+		return -ENOMEM;
+	}
+
+	port->private = od;
+
+	/* Start reading from the device */
+	if (usb_submit_urb(port->read_urb))
+		dbg("usb_submit_urb(read bulk, %p) failed", port->read_urb);
+
+	wport->tty = port->tty;
+
+	return (0);
+}
+
+static void omninet_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial 	*serial = port->serial;
+	struct usb_serial_port 	*wport 	= &serial->port[1];
+	struct omninet_data 	*od 	= (struct omninet_data *) port->private;
+
+	port->active = 0;
+
+
+	dbg("zyxel_close port %d", port->number);
+
+	usb_unlink_urb (wport->write_urb);
+	usb_unlink_urb (port->read_urb);
+
+	if(od) kfree(od);
+}
+
+
+#define OMNINET_DATAOFFSET	0x04
+#define OMNINET_HEADERLEN	sizeof(struct omninet_header)
+#define OMNINET_BULKOUTSIZE 	(64 - OMNINET_HEADERLEN)
+
+static void omninet_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port 	*port 	= (struct usb_serial_port *)urb->context;
+	struct usb_serial 	*serial = port->serial;
+
+	unsigned char 		*data 	= urb->transfer_buffer;
+	struct omninet_header 	*header = (struct omninet_header *) &data[0];
+
+	int i;
+
+//	dbg("omninet_read_bulk_callback");
+
+	if (port_paranoia_check (port, "omninet_read_bulk_callback")) {
+		return;
+	}
+
+	if (serial_paranoia_check (serial, "omninet_read_bulk_callback")) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg("nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if(header->oh_xxx != 0x30)
+	{
+		if (urb->actual_length) {
+			printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len);
+			for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) {
+				printk ("%.2x ", data[i]);
+			}
+			printk ("\n");
+		}
+	}
+#endif
+
+	if (urb->actual_length && header->oh_len)
+	{
+		for (i = 0; i < header->oh_len; i++) {
+			 tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0);
+	  	}
+	  	tty_flip_buffer_push(port->tty);
+	}
+
+	/* Continue trying to always read  */
+	if (usb_submit_urb(urb))
+		dbg("failed resubmitting read urb");
+
+	return;
+}
+
+static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial 	*serial	= port->serial;
+	struct usb_serial_port 	*wport	= &serial->port[1];
+
+	struct omninet_data 	*od 	= (struct omninet_data   *) port->private;
+	struct omninet_header	*header = (struct omninet_header *) wport->write_urb->transfer_buffer;
+/*
+#ifdef DEBUG
+	int i;
+#endif
+*/
+
+//	dbg("omninet_write port %d", port->number);
+
+	if (count == 0) {
+		dbg("write request of 0 bytes");
+		return (0);
+	}
+/*
+#ifdef DEBUG
+	printk (KERN_DEBUG __FILE__ ": omninet_write %d: ", count);
+		for (i = 0; i < count; i++) {
+			if( isalpha(buf[i]) )
+				printk ("%c ", buf[i]);
+			else
+				printk ("%.2x ", buf[i]);
+		}
+		printk ("\n");
+#endif
+*/
+	if (wport->write_urb->status == -EINPROGRESS) {
+		dbg ("already writing");
+		return (0);
+	}
+
+	count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
+
+	if (from_user) {
+		copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+	}
+	else {
+		memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+	}
+
+
+	header->oh_seq 	= od->od_outseq++;
+	header->oh_len 	= count;
+	header->oh_xxx  = 0x03;
+	header->oh_pad 	= 0x00;
+
+	/* send the data out the bulk port, always 64 bytes */
+	wport->write_urb->transfer_buffer_length = 64;
+
+	if (usb_submit_urb(wport->write_urb))
+		dbg("usb_submit_urb(write bulk) failed");
+
+//	dbg("omninet_write returns %d", count);
+
+	return (count);
+}
+
+
+static int omninet_write_room (struct usb_serial_port *port)
+{
+	struct usb_serial 	*serial = port->serial;
+	struct usb_serial_port 	*wport 	= &serial->port[1];
+
+	int room = 0; // Default: no room
+
+	if (wport->write_urb->status != -EINPROGRESS)
+		room = wport->bulk_out_size - OMNINET_HEADERLEN;
+
+//	dbg("omninet_write_room returns %d", room);
+
+	return (room);
+}
+
+static void omninet_write_bulk_callback (struct urb *urb)
+{
+/*	struct omninet_header	*header = (struct omninet_header  *) urb->transfer_buffer; */
+	struct usb_serial_port 	*port   = (struct usb_serial_port *) urb->context;
+	struct usb_serial 	*serial;
+	struct tty_struct 	*tty;
+
+//	dbg("omninet_write_bulk_callback, port %0x\n", port);
+
+
+	if (port_paranoia_check (port, "omninet_write_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "omninet_write_bulk_callback")) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg("nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	tty = port->tty;
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+
+//	dbg("omninet_write_bulk_callback, tty %0x\n", tty);
+
+	return;
+}
+
+#endif	/* CONFIG_USB_SERIAL_OMNINET */
+
+
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h
--- v2.3.99-pre5/linux/drivers/usb/serial/usb-serial.h	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/usb-serial.h	Fri Apr 21 14:03:01 2000
@@ -39,10 +39,8 @@
 	unsigned char		number;
 	char			active;		/* someone has this device open */
 
-	struct usb_endpoint_descriptor * interrupt_in_endpoint;
-	__u8			interrupt_in_interval;
 	unsigned char *		interrupt_in_buffer;
-	struct urb *		control_urb;
+	struct urb *		interrupt_in_urb;
 
 	unsigned char *		bulk_in_buffer;
 	struct urb *		read_urb;
@@ -50,7 +48,10 @@
 	unsigned char *		bulk_out_buffer;
 	int			bulk_out_size;
 	struct urb *		write_urb;
-	void *			private;	/* data private to the specific driver */
+
+	wait_queue_head_t	write_wait;
+
+	void *			private;	/* data private to the specific port */
 };
 
 struct usb_serial {
@@ -65,11 +66,6 @@
 	char				num_bulk_out;		/* number of bulk out endpoints we have */
 	struct usb_serial_port		port[MAX_NUM_PORTS];
 
-	/* FIXME! These should move to the private area of the keyspan driver */
-	int			tx_room;
-	int			tx_throttled;
-	wait_queue_head_t 	write_wait;
-
 	void *			private;		/* data private to the specific driver */
 };
 
@@ -99,7 +95,8 @@
 
 	/* function call to make before accepting driver */
 	int (*startup) (struct usb_serial *serial);	/* return 0 to continue initialization, anything else to abort */
-	
+	void (*shutdown) (struct usb_serial *serial);
+
 	/* serial function calls */
 	int  (*open)		(struct usb_serial_port *port, struct file * filp);
 	void (*close)		(struct usb_serial_port *port, struct file * filp);
@@ -111,7 +108,8 @@
 	int  (*chars_in_buffer)	(struct usb_serial_port *port);
 	void (*throttle)	(struct usb_serial_port *port);
 	void (*unthrottle)	(struct usb_serial_port *port);
-	
+
+	void (*read_int_callback)(struct urb *urb);
 	void (*read_bulk_callback)(struct urb *urb);
 	void (*write_bulk_callback)(struct urb *urb);
 };
@@ -124,6 +122,7 @@
 extern struct usb_serial_device_type ftdi_sio_device;
 extern struct usb_serial_device_type keyspan_pda_fake_device;
 extern struct usb_serial_device_type keyspan_pda_device;
+extern struct usb_serial_device_type zyxel_omninet_device;
 
 
 /* determine if we should include the EzUSB loader functions */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.3.99-pre5/linux/drivers/usb/serial/usbserial.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/serial/usbserial.c	Mon Apr 24 16:15:01 2000
@@ -14,6 +14,14 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (04/23/2000) gkh
+ *	Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
+ *	Moved when the startup code printed out the devices that are supported.
+ *
+ * (04/19/2000) gkh
+ *	Added driver for ZyXEL omni.net lcd plus ISDN TA
+ *	Made startup info message specify which drivers were compiled in.
+ *
  * (04/03/2000) gkh
  *	Changed the probe process to remove the module unload races.
  *	Changed where the tty layer gets initialized to have devfs work nicer.
@@ -211,6 +219,7 @@
 
 #include "usb-serial.h"
 
+#define MAX(a,b)	(((a)>(b))?(a):(b))
 
 /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
 /* need to always compile these in, as some of the other devices use these functions as their own. */
@@ -270,6 +279,9 @@
 	&keyspan_pda_fake_device,
 	&keyspan_pda_device,
 #endif
+#ifdef CONFIG_USB_SERIAL_OMNINET
+	&zyxel_omninet_device,
+#endif
 	NULL
 };
 
@@ -424,14 +436,9 @@
 		return -ENODEV;
 	}
 
-	/* set up our port structure */
+	/* set up our port structure making the tty driver remember our port object, and us it */
 	portNumber = MINOR(tty->device) - serial->minor;
 	port = &serial->port[portNumber];
-	port->number = portNumber;
-	port->serial = serial;
-	port->magic = USB_SERIAL_PORT_MAGIC;
-	
-	/* make the tty driver remember our port object, and us it */
 	tty->driver_data = port;
 	port->tty = tty;
 	 
@@ -996,236 +1003,248 @@
 	int num_bulk_in = 0;
 	int num_bulk_out = 0;
 	int num_ports;
+	int max_endpoints;
 	
-	/* loop through our list of known serial converters, and see if this device matches */
-	device_num = 0;
-	while (usb_serial_devices[device_num] != NULL) {
+	/* loop through our list of known serial converters, and see if this
+           device matches. */
+	for (device_num = 0; usb_serial_devices[device_num]; device_num++) {
 		type = usb_serial_devices[device_num];
-		dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+		dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", 
+		     type->name, *(type->idVendor), *(type->idProduct));
 
 		/* look at the device descriptor */
 		if ((dev->descriptor.idVendor == *(type->idVendor)) &&
 		    (dev->descriptor.idProduct == *(type->idProduct))) {
+			dbg("descriptor matches");
+			break;
+		}
+	}
+	if (!usb_serial_devices[device_num]) {
+		/* no match */
+		dbg("none matched");
+		return(NULL);
+	}
 
-			dbg("descriptor matches...looking at the endpoints");
-
-			/* descriptor matches, let's try to find the endpoints needed */
-			interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+	/* descriptor matches, let's find the endpoints needed */
+	interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
 			
-			/* check out the endpoints */
-			interface = &dev->actconfig->interface[ifnum].altsetting[0];
-			for (i = 0; i < interface->bNumEndpoints; ++i) {
-				endpoint = &interface->endpoint[i];
-		
-				if ((endpoint->bEndpointAddress & 0x80) &&
-				    ((endpoint->bmAttributes & 3) == 0x02)) {
-					/* we found a bulk in endpoint */
-					dbg("found bulk in");
-					bulk_in_pipe = HAS;
-					bulk_in_endpoint[num_bulk_in] = endpoint;
-					++num_bulk_in;
-				}
-
-				if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-				    ((endpoint->bmAttributes & 3) == 0x02)) {
-					/* we found a bulk out endpoint */
-					dbg("found bulk out");
-					bulk_out_pipe = HAS;
-					bulk_out_endpoint[num_bulk_out] = endpoint;
-					++num_bulk_out;
-				}
+	/* check out the endpoints */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	for (i = 0; i < interface->bNumEndpoints; ++i) {
+		endpoint = &interface->endpoint[i];
 		
-				if ((endpoint->bEndpointAddress & 0x80) &&
-				    ((endpoint->bmAttributes & 3) == 0x03)) {
-					/* we found a interrupt in endpoint */
-					dbg("found interrupt in");
-					interrupt_pipe = HAS;
-					interrupt_in_endpoint[num_interrupt_in] = endpoint;
-					++num_interrupt_in;
-				}
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk in endpoint */
+			dbg("found bulk in");
+			bulk_in_pipe = HAS;
+			bulk_in_endpoint[num_bulk_in] = endpoint;
+			++num_bulk_in;
+		}
 
-			}
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk out endpoint */
+			dbg("found bulk out");
+			bulk_out_pipe = HAS;
+			bulk_out_endpoint[num_bulk_out] = endpoint;
+			++num_bulk_out;
+		}
+		
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found a interrupt in endpoint */
+			dbg("found interrupt in");
+			interrupt_pipe = HAS;
+			interrupt_in_endpoint[num_interrupt_in] = endpoint;
+			++num_interrupt_in;
+		}
+	}
 	
-			/* verify that we found all of the endpoints that we need */
-			if ((interrupt_pipe & type->needs_interrupt_in) &&
-			    (bulk_in_pipe & type->needs_bulk_in) &&
-			    (bulk_out_pipe & type->needs_bulk_out)) {
-				/* found all that we need */
-				MOD_INC_USE_COUNT;
-				info("%s converter detected", type->name);
+	/* verify that we found all of the endpoints that we need */
+	if (!((interrupt_pipe & type->needs_interrupt_in) &&
+	      (bulk_in_pipe & type->needs_bulk_in) &&
+	      (bulk_out_pipe & type->needs_bulk_out))) {
+		/* nope, they don't match what we expected */
+		info("descriptors matched, but endpoints did not");
+		return NULL;
+	}
 
-#ifdef CONFIG_USB_SERIAL_GENERIC
-				if (type == &generic_device)
-					num_ports = num_bulk_out;
-				else
-#endif
-					num_ports = type->num_ports;
+	/* found all that we need */
+	MOD_INC_USE_COUNT;
+	info("%s converter detected", type->name);
 
-				serial = get_free_serial (num_ports, &minor);
-				if (serial == NULL) {
-					err("No more free serial devices");
-					MOD_DEC_USE_COUNT;
-					return NULL;
-				}
-	
-			       	serial->dev = dev;
-				serial->type = type;
-				serial->minor = minor;
-				serial->num_ports = num_ports;
-				serial->num_bulk_in = num_bulk_in;
-				serial->num_bulk_out = num_bulk_out;
-				serial->num_interrupt_in = num_interrupt_in;
-
-				/* initialize a tty_driver for this device */
-				serial->tty_driver = usb_serial_tty_driver_init (serial);
-				if (serial->tty_driver == NULL) {
-					err("Can't create a tty_serial_driver");
-					goto probe_error;
-				}
-
-				if (tty_register_driver (serial->tty_driver)) {
-					err("failed to register tty driver");
-					goto probe_error;
-				}
-
-				/* collect interrupt_in endpoints now, because
-				   the keyspan_pda startup function needs
-				   to know about them */
-				for (i = 0; i < num_interrupt_in; ++i) {
-					port = &serial->port[i];
-					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
-					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->interrupt_in_buffer) {
-						err("Couldn't allocate interrupt_in_buffer");
-						goto probe_error;
-					}
-					port->interrupt_in_endpoint = interrupt_in_endpoint[i];
-				}
-
-				/* if this device type has a startup function, call it */
-				if (type->startup) {
-					if (type->startup (serial)) {
-						goto probe_error;
-					}
-				}
-
-				/* set up the endpoint information */
-				for (i = 0; i < num_bulk_in; ++i) {
-					port = &serial->port[i];
-					port->read_urb = usb_alloc_urb (0);
-					if (!port->read_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
-					port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->bulk_in_buffer) {
-						err("Couldn't allocate bulk_in_buffer");
-						goto probe_error;
-					}
-					if (serial->type->read_bulk_callback) {
-						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
-					} else {
-						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
-					}
-				}
-
-				for (i = 0; i < num_bulk_out; ++i) {
-					port = &serial->port[i];
-					port->write_urb = usb_alloc_urb(0);
-					if (!port->write_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
-					port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
-					if (!port->bulk_out_buffer) {
-						err("Couldn't allocate bulk_out_buffer");
-						goto probe_error;
-					}
-					if (serial->type->write_bulk_callback) {
-						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
-					} else {
-						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
-					}
-				}
-
-#if 0 /* use this code when WhiteHEAT is up and running */
-				for (i = 0; i < num_interrupt_in; ++i) {
-					port = &serial->port[i];
-					port->control_urb = usb_alloc_urb(0);
-					if (!port->control_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
-					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->interrupt_in_buffer) {
-						err("Couldn't allocate interrupt_in_buffer");
-						goto probe_error;
-					}
-					FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
-							port->interrupt_in_buffer, buffer_size, serial_control_irq,
-							port, interrupt_in_endpoint[i]->bInterval);
-				}
+#ifdef CONFIG_USB_SERIAL_GENERIC
+	if (type == &generic_device) {
+		num_ports = num_bulk_out;
+		if (num_ports == 0) {
+			err("Generic device with no bulk out, not allowed.");
+			MOD_DEC_USE_COUNT;
+			return NULL;
+		}
+	} else
 #endif
+		num_ports = type->num_ports;
 
-				for (i = 0; i < serial->num_ports; ++i) {
-					info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
-				}
-
-				return serial;
-			} else {
-				info("descriptors matched, but endpoints did not");
-			}
+	serial = get_free_serial (num_ports, &minor);
+	if (serial == NULL) {
+		err("No more free serial devices");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+	
+	serial->dev = dev;
+	serial->type = type;
+	serial->minor = minor;
+	serial->num_ports = num_ports;
+	serial->num_bulk_in = num_bulk_in;
+	serial->num_bulk_out = num_bulk_out;
+	serial->num_interrupt_in = num_interrupt_in;
+
+	/* initialize a tty_driver for this device */
+	serial->tty_driver = usb_serial_tty_driver_init (serial);
+	if (serial->tty_driver == NULL) {
+		err("Can't create a tty_serial_driver");
+		goto probe_error;
+	}
+
+	if (tty_register_driver (serial->tty_driver)) {
+		err("failed to register tty driver");
+		goto probe_error;
+	}
+	
+	/* if this device type has a startup function, call it */
+	if (type->startup) {
+		if (type->startup (serial)) {
+			goto probe_error;
 		}
-
-		/* look at the next type in our list */
-		++device_num;
 	}
 
-probe_error:
-	if (serial) {
-		for (i = 0; i < num_bulk_in; ++i) {
-			port = &serial->port[i];
-			if (port->read_urb)
-				usb_free_urb (port->read_urb);
-			if (serial->port[i].bulk_in_buffer[i])
-				kfree (serial->port[i].bulk_in_buffer);
+	/* set up the endpoint information */
+	for (i = 0; i < num_bulk_in; ++i) {
+		endpoint = bulk_in_endpoint[i];
+		port = &serial->port[i];
+		port->read_urb = usb_alloc_urb (0);
+		if (!port->read_urb) {
+			err("No free urbs available");
+			goto probe_error;
 		}
-		for (i = 0; i < num_bulk_out; ++i) {
-			port = &serial->port[i];
-			if (port->write_urb)
-				usb_free_urb (port->write_urb);
-			if (serial->port[i].bulk_out_buffer)
-				kfree (serial->port[i].bulk_out_buffer);
+		buffer_size = endpoint->wMaxPacketSize;
+		port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->bulk_in_buffer) {
+			err("Couldn't allocate bulk_in_buffer");
+			goto probe_error;
 		}
-		for (i = 0; i < num_interrupt_in; ++i) {
-			port = &serial->port[i];
-			if (port->control_urb)
-				usb_free_urb (port->control_urb);
-			if (serial->port[i].interrupt_in_buffer)
-				kfree (serial->port[i].interrupt_in_buffer);
+		FILL_BULK_URB(port->read_urb, dev, 
+			      usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+			      port->bulk_in_buffer, buffer_size, 
+			      ((serial->type->read_bulk_callback) ?
+			       serial->type->read_bulk_callback :
+			       generic_read_bulk_callback), 
+			      port);
+	}
+
+	for (i = 0; i < num_bulk_out; ++i) {
+		endpoint = bulk_out_endpoint[i];
+		port = &serial->port[i];
+		port->write_urb = usb_alloc_urb(0);
+		if (!port->write_urb) {
+			err("No free urbs available");
+			goto probe_error;
 		}
-		
-		/* return the minor range that this device had */
-		return_serial (serial);
-
-		/* if this device has a tty_driver, then unregister it and free it */
-		if (serial->tty_driver) {
-			tty_unregister_driver (serial->tty_driver);
-			kfree (serial->tty_driver);
-			serial->tty_driver = NULL;
+		buffer_size = endpoint->wMaxPacketSize;
+		port->bulk_out_size = buffer_size;
+		port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->bulk_out_buffer) {
+			err("Couldn't allocate bulk_out_buffer");
+			goto probe_error;
+		}
+		FILL_BULK_URB(port->write_urb, dev, 
+			      usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
+			      port->bulk_out_buffer, buffer_size,
+			      ((serial->type->write_bulk_callback) ? 
+			       serial->type->write_bulk_callback : 
+			       generic_write_bulk_callback), 
+			      port);
+	}
+
+	for (i = 0; i < num_interrupt_in; ++i) {
+		endpoint = interrupt_in_endpoint[i];
+		port = &serial->port[i];
+		port->interrupt_in_urb = usb_alloc_urb(0);
+		if (!port->interrupt_in_urb) {
+			err("No free urbs available");
+			goto probe_error;
 		}
+		buffer_size = endpoint->wMaxPacketSize;
+		port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->interrupt_in_buffer) {
+			err("Couldn't allocate interrupt_in_buffer");
+			goto probe_error;
+		}
+		FILL_INT_URB(port->interrupt_in_urb, dev, 
+			     usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+			     port->interrupt_in_buffer, buffer_size, 
+			     serial->type->read_int_callback,
+			     port, 
+			     endpoint->bInterval);
+	}
+
+	/* initialize some parts of the port structures */
+	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
+	max_endpoints = MAX(num_bulk_in, num_bulk_out);
+	max_endpoints = MAX(max_endpoints, num_interrupt_in);
+	for (i = 0; i < max_endpoints; ++i) {
+		port = &serial->port[i];
+		port->number = i;
+		port->serial = serial;
+		port->magic = USB_SERIAL_PORT_MAGIC;
+	}
+	
+	for (i = 0; i < serial->num_ports; ++i) {
+		info("%s converter now attached to ttyUSB%d", 
+		     type->name, serial->minor + i);
+	}
+	
+	return serial; /* success */
 
-		/* free up any memory that we allocated */
-		kfree (serial);
-		MOD_DEC_USE_COUNT;
+
+probe_error:
+	for (i = 0; i < num_bulk_in; ++i) {
+		port = &serial->port[i];
+		if (port->read_urb)
+			usb_free_urb (port->read_urb);
+		if (port->bulk_in_buffer)
+			kfree (port->bulk_in_buffer);
+	}
+	for (i = 0; i < num_bulk_out; ++i) {
+		port = &serial->port[i];
+		if (port->write_urb)
+			usb_free_urb (port->write_urb);
+		if (port->bulk_out_buffer)
+			kfree (port->bulk_out_buffer);
+	}
+	for (i = 0; i < num_interrupt_in; ++i) {
+		port = &serial->port[i];
+		if (port->interrupt_in_urb)
+			usb_free_urb (port->interrupt_in_urb);
+		if (port->interrupt_in_buffer)
+			kfree (port->interrupt_in_buffer);
 	}
+		
+	/* return the minor range that this device had */
+	return_serial (serial);
+
+	/* if this device has a tty_driver, then unregister it and free it */
+	if (serial->tty_driver) {
+		tty_unregister_driver (serial->tty_driver);
+		kfree (serial->tty_driver);
+		serial->tty_driver = NULL;
+	}
+
+	/* free up any memory that we allocated */
+	kfree (serial);
+	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -1237,6 +1256,9 @@
 	int i;
 
 	if (serial) {
+		if (serial->type->shutdown)
+			serial->type->shutdown(serial);
+
 		for (i = 0; i < serial->num_ports; ++i)
 			serial->port[i].active = 0;
 
@@ -1260,9 +1282,9 @@
 		}
 		for (i = 0; i < serial->num_interrupt_in; ++i) {
 			port = &serial->port[i];
-			if (port->control_urb) {
-				usb_unlink_urb (port->control_urb);
-				usb_free_urb (port->control_urb);
+			if (port->interrupt_in_urb) {
+				usb_unlink_urb (port->interrupt_in_urb);
+				usb_free_urb (port->interrupt_in_urb);
 			}
 			if (port->interrupt_in_buffer)
 				kfree (port->interrupt_in_buffer);
@@ -1295,18 +1317,32 @@
 int usb_serial_init(void)
 {
 	int i;
+	int something;
+	int result;
 
 	/* Initalize our global data */
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		serial_table[i] = NULL;
 	}
 
+	/* tell the world what devices this driver currently supports */
+	something = 0;
+	for (i = 0; usb_serial_devices[i]; ++i) {
+		if (!strstr (usb_serial_devices[i]->name, "prerenumeration")) {
+			info ("USB Serial support registered for %s", usb_serial_devices[i]->name);
+			something = 1;
+		}
+	}
+	if (!something)
+		info ("USB Serial driver is not configured for any devices!");
+
 	/* register the USB driver */
-	if (usb_register(&usb_serial_driver) < 0) {
+	result = usb_register(&usb_serial_driver);
+	if (result < 0) {
+		err("usb_register failed for the usb-serial driver. Error number %d", result);
 		return -1;
 	}
-
-	info("support registered");
+	
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/uhci-debug.h linux/drivers/usb/uhci-debug.h
--- v2.3.99-pre5/linux/drivers/usb/uhci-debug.h	Sun Feb 20 21:12:39 2000
+++ linux/drivers/usb/uhci-debug.h	Mon Apr 24 16:15:01 2000
@@ -14,7 +14,7 @@
 
 #include "uhci.h"
 
-void uhci_show_td(struct uhci_td * td)
+void uhci_show_td(struct uhci_td *td)
 {
 	char *spid;
 
@@ -127,6 +127,62 @@
 		return NULL;
 
 	return bus_to_virt(link & ~UHCI_PTR_BITS);
+}
+
+void uhci_show_urb_queue(struct urb *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct list_head *head, *tmp;
+	int i, checked = 0, prevactive = 0;
+
+	printk("  URB [%p] urbp [%p]\n", urb, urbp);
+
+	if (urbp->qh)
+		printk("    QH [%p]\n", urbp->qh);
+	else
+		printk("    QH [%p] element (%08x) link (%08x)\n", urbp->qh,
+			urbp->qh->element, urbp->qh->link);
+
+	i = 0;
+
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		printk("      td %d: [%p]\n", i++, td);
+		printk("      ");
+		uhci_show_td(td);
+
+		if (i > 10 && !checked && prevactive && tmp != head) {
+			struct list_head *ntmp = tmp;
+			struct uhci_td *ntd = td;
+			int active = 1, ni = i;
+
+			checked = 1;
+
+			while (ntmp != head && ntmp->next != head && active) {
+				ntd = list_entry(ntmp, struct uhci_td, list);
+
+				ntmp = ntmp->next;
+
+				active = ntd->status & TD_CTRL_ACTIVE;
+
+				ni++;
+			}
+
+			if (active && ni > i) {
+				printk("      [skipped %d active TD's]\n", ni - i);
+				tmp = ntmp;
+				td = ntd;
+				i = ni;
+			}
+		}
+
+		prevactive = td->status & TD_CTRL_ACTIVE;
+	}
 }
 
 void uhci_show_queue(struct uhci_qh *qh)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.99-pre5/linux/drivers/usb/uhci.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/uhci.c	Mon Apr 24 16:15:01 2000
@@ -284,42 +284,6 @@
 	prevtd->link = UHCI_PTR_TERM;
 }
 
-/* This function will append one URB's QH to another URB's QH. This is for */
-/*  USB_QUEUE_BULK support */
-static void uhci_append_urb_qh(struct uhci *uhci, struct urb *eurb, struct urb *urb)
-{
-	struct urb *nurb;
-	struct urb_priv *eurbp, *urbp, *nurbp;
-	struct list_head *tmp;
-	struct uhci_td *td, *ntd;
-	unsigned long flags;
-
-	eurbp = eurb->hcpriv;
-	urbp = urb->hcpriv;
-
-	spin_lock_irqsave(&eurb->lock, flags);
-
-	/* Grab the last URB in the queue */
-	tmp = eurbp->urb_queue_list.prev;
-
-	/* Add this one to the end */
-	list_add_tail(&urbp->urb_queue_list, &eurbp->urb_queue_list);
-
-	spin_unlock_irqrestore(&eurb->lock, flags);
-
-	nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
-	nurb = nurbp->urb;
-
-	tmp = nurbp->list.prev;
-	td = list_entry(tmp, struct uhci_td, list);
-
-	tmp = urbp->list.next;
-	ntd = list_entry(tmp, struct uhci_td, list);
-
-	/* No breadth since this will only be called for bulk transfers */
-	td->link = virt_to_bus(ntd);
-}
-
 static void uhci_free_td(struct uhci_td *td)
 {
 	if (!list_empty(&td->list))
@@ -395,6 +359,7 @@
 	if (qh->nextqh)
 		qh->nextqh->prevqh = qh->prevqh;
 	qh->prevqh = qh->nextqh = NULL;
+	qh->element = qh->link = UHCI_PTR_TERM;
 	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 
 	if (delayed) {
@@ -413,6 +378,101 @@
 		uhci_free_qh(qh);
 }
 
+static spinlock_t uhci_append_urb_lock = SPIN_LOCK_UNLOCKED;
+
+/* This function will append one URB's QH to another URB's QH. This is for */
+/*  USB_QUEUE_BULK support */
+static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
+{
+	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+	struct list_head *tmp;
+	struct uhci_td *td, *ltd;
+	unsigned long flags;
+
+	eurbp = eurb->hcpriv;
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci_append_urb_lock, flags);
+
+	/* Find the beginning URB in the queue */
+	if (eurbp->queued) {
+		struct list_head *head = &eurbp->urb_queue_list;
+
+		tmp = head->next;
+		while (tmp != head) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, urb_queue_list);
+
+			tmp = tmp->next;
+
+			if (!turbp->queued)
+				break;
+		}
+	} else
+		tmp = &eurbp->urb_queue_list;
+
+	furbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+
+	tmp = furbp->urb_queue_list.prev;
+	lurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+
+	/* Add this one to the end */
+	list_add_tail(&urbp->urb_queue_list, &furbp->urb_queue_list);
+
+	/* Grab the last TD from the last URB */
+	ltd = list_entry(lurbp->list.prev, struct uhci_td, list);
+
+	/* Grab the first TD from the first URB */
+	td = list_entry(urbp->list.next, struct uhci_td, list);
+
+	/* No breadth since this will only be called for bulk transfers */
+	ltd->link = virt_to_bus(td);
+
+	spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
+}
+
+static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp, *nurbp;
+	unsigned long flags;
+
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci_append_urb_lock, flags);
+
+	nurbp = list_entry(urbp->urb_queue_list.next, struct urb_priv,
+			urb_queue_list);
+
+	if (!urbp->queued) {
+		/* We're the head, so just insert the QH for the next URB */
+		uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
+		nurbp->queued = 0;
+	} else {
+		struct urb_priv *purbp;
+		struct uhci_td *ptd;
+
+		/* We're somewhere in the middle (or end). A bit trickier */
+		/*  than the head scenario */
+		purbp = list_entry(urbp->urb_queue_list.prev, struct urb_priv,
+				urb_queue_list);
+
+		ptd = list_entry(purbp->list.prev, struct uhci_td, list);
+		if (nurbp->queued)
+			/* Close the gap between the two */
+			ptd->link = virt_to_bus(list_entry(nurbp->list.next,
+					struct uhci_td, list));
+		else
+			/* The next URB happens to be the beggining, so */
+			/*  we're the last, end the chain */
+			ptd->link = UHCI_PTR_TERM;
+		
+	}
+
+	list_del(&urbp->urb_queue_list);
+
+	spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
+}
+
 struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
 {
 	struct urb_priv *urbp;
@@ -491,11 +551,6 @@
 		uhci_free_td(td);
 	}
 
-	if (!list_empty(&urbp->urb_queue_list)) {
-		list_del(&urbp->urb_queue_list);
-		INIT_LIST_HEAD(&urbp->urb_queue_list);
-	}
-
 	urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 
@@ -672,12 +727,10 @@
 	if (urb->pipe & TD_CTRL_LS) {
 		uhci_insert_tds_in_qh(qh, urb, 0);
 		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
-		urbp->queued = 0;
 	} else {
 		uhci_insert_tds_in_qh(qh, urb, 1);
 		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
 		uhci_inc_fsbr(uhci, urb);
-		urbp->queued = 0;
 	}
 
 	urbp->qh = qh;
@@ -697,18 +750,21 @@
 	struct urb_priv *urbp = urb->hcpriv;
 	struct uhci_td *td;
 	unsigned int status;
+	int ret = 0;
 
 	if (!urbp)
 		return -EINVAL;
 
 	head = &urbp->list;
-	tmp = head->next;
-	if (head == tmp)
+	if (head->next == head)
 		return -EINVAL;
 
-	if (urbp->short_control_packet)
+	if (urbp->short_control_packet) {
+		tmp = head->prev;
 		goto status_phase;
+	}
 
+	tmp = head->next;
 	td = list_entry(tmp, struct uhci_td, list);
 
 	/* The first TD is the SETUP phase, check the status, but skip */
@@ -729,20 +785,34 @@
 
 		tmp = tmp->next;
 
+		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
+		    !(td->status & TD_CTRL_ACTIVE)) {
+			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
+			urbp->fsbr_timeout = 0;
+			td->status &= ~TD_CTRL_IOC;
+		}
+
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
 
 		urb->actual_length += uhci_actual_length(td->status);
 
-		/* If SPD is set then we received a short packet */
-		/*  There will be no status phase at the end */
-		if ((td->status & TD_CTRL_SPD) &&
-		    (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
-			return usb_control_retrigger_status(urb);
-
 		if (status)
 			goto td_error;
+
+		/* Check to see if we received a short packet */
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			}
+
+			if (uhci_packetid(td->info) == USB_PID_IN)
+				return usb_control_retrigger_status(urb);
+			else
+				return 0;
+		}
 	}
 
 status_phase:
@@ -768,19 +838,22 @@
 	return 0;
 
 td_error:
-	if (status & TD_CTRL_STALLED)
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
 		/* endpoint has stalled - mark it halted */
 		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
 	    			uhci_packetout(td->info));
-	else if (debug) {
+
+err:
+	if (debug && ret != -EPIPE) {
 		/* Some debugging code */
 		dbg("uhci_result_control() failed with status %x", status);
 
 		/* Print the chain for debugging purposes */
-		uhci_show_queue(urbp->qh);
+		uhci_show_urb_queue(urb);
 	}
 
-	return uhci_map_status(status, uhci_packetout(td->info));
+	return ret;
 }
 
 static int usb_control_retrigger_status(struct urb *urb)
@@ -823,7 +896,6 @@
 		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh);
 	else
 		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh);
-	urbp->queued = 0;
 
 	return -EINPROGRESS;
 }
@@ -869,8 +941,9 @@
 {
 	struct list_head *tmp, *head;
 	struct urb_priv *urbp = urb->hcpriv;
-	unsigned int status;
 	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
 
 	if (!urbp)
 		return -EINVAL;
@@ -884,46 +957,58 @@
 
 		tmp = tmp->next;
 
+		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
+		    !(td->status & TD_CTRL_ACTIVE)) {
+			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
+			urbp->fsbr_timeout = 0;
+			td->status &= ~TD_CTRL_IOC;
+		}
+
 		status = uhci_status_bits(td->status);
 		if (status & TD_CTRL_ACTIVE)
 			return -EINPROGRESS;
 
 		urb->actual_length += uhci_actual_length(td->status);
 
-		/* If SPD is set then we received a short packet */
-		if ((td->status & TD_CTRL_SPD) &&
-		    (uhci_actual_length(td->status) < uhci_expected_length(td->info))) {
+		if (status)
+			goto td_error;
+
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
 			usb_settoggle(urb->dev, uhci_endpoint(td->info),
 				uhci_packetout(td->info),
 				uhci_toggle(td->info) ^ 1);
 
-			return 0;
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			} else
+				return 0;
 		}
-
-		if (status)
-			goto td_error;
 	}
 
 	return 0;
 
 td_error:
-	if (status & TD_CTRL_STALLED)
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
 		/* endpoint has stalled - mark it halted */
 		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
 	    			uhci_packetout(td->info));
-	else if (debug) {
+
+err:
+	if (debug && ret != -EPIPE) {
 		/* Some debugging code */
 		dbg("uhci_result_interrupt/bulk() failed with status %x",
 			status);
 
 		/* Print the chain for debugging purposes */
 		if (urbp->qh)
-			uhci_show_queue(urbp->qh);
+			uhci_show_urb_queue(urb);
 		else
 			uhci_show_td(td);
 	}
 
-	return uhci_map_status(status, uhci_packetout(td->info));
+	return ret;
 }
 
 static void uhci_reset_interrupt(struct urb *urb)
@@ -974,6 +1059,7 @@
 
 	/* 3 errors */
 	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
+
 	if (!(urb->transfer_flags & USB_DISABLE_SPD))
 		status |= TD_CTRL_SPD;
 
@@ -1016,12 +1102,10 @@
 	uhci_insert_tds_in_qh(qh, urb, 1);
 
 	if (urb->transfer_flags & USB_QUEUE_BULK && eurb) {
-		uhci_append_urb_qh(uhci, eurb, urb);
 		urbp->queued = 1;
-	} else {
+		uhci_append_queued_urb(uhci, eurb, urb);
+	} else
 		uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
-		urbp->queued = 0;
-	}
 
 	uhci_add_urb_list(uhci, urb);
 
@@ -1049,6 +1133,8 @@
 	while (tmp != head) {
 		struct urb *u = list_entry(tmp, struct urb, urb_list);
 
+		tmp = tmp->next;
+
 		/* look for pending URB's with identical pipe handle */
 		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
 		    (u->status == -EINPROGRESS) && (u != urb)) {
@@ -1056,7 +1142,6 @@
 				*start = u->start_frame;
 			last_urb = u;
 		}
-		tmp = tmp->next;
 	}
 
 	if (last_urb) {
@@ -1363,14 +1448,8 @@
 		/* The interrupt loop will reclaim the QH's */
 		uhci_remove_qh(uhci, urbp->qh);
 
-	if (!list_empty(&urbp->urb_queue_list)) {
-		struct list_head *tmp = urbp->urb_queue_list.next;
-		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
-		if (nurbp->queued) {
-			uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
-			nurbp->queued = 0;
-		}
-	}
+	if (!list_empty(&urbp->urb_queue_list))
+		uhci_delete_queued_urb(uhci, urb);
 
 	uhci_destroy_urb_priv(urb);
 
@@ -1430,6 +1509,35 @@
 	return ret;
 }
 
+static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+
+	uhci_dec_fsbr(uhci, urb);
+
+	/* There is a race with updating IOC in here, but it's not worth */
+	/*  trying to fix since this is merely an optimization. The only */
+	/*  time we'd lose is if the status of the packet got updated */
+	/*  and we'd be turning on FSBR next frame anyway, so it's a wash */
+	urbp->fsbr_timeout = 1;
+
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		if (td->status & TD_CTRL_ACTIVE) {
+			td->status |= TD_CTRL_IOC;
+			break;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * uhci_get_current_frame_number()
  *
@@ -1586,7 +1694,7 @@
 		if (urbp) {
 			/* Check if the FSBR timed out */
 			if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
-				uhci_dec_fsbr(uhci, u);
+				uhci_fsbr_timeout(uhci, u);
 
 			/* Check if the URB timed out */
 			if (u->timeout && time_after(u->timeout, jiffies)) {
@@ -1762,7 +1870,7 @@
 		case RH_PORT_POWER:
 			OK(0); /* port power ** */
 		case RH_PORT_ENABLE:
-			SET_RH_PORTSTAT (USBPORTSC_PE);
+			SET_RH_PORTSTAT(USBPORTSC_PE);
 			OK(0);
 		}
 		break;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.99-pre5/linux/drivers/usb/uhci.h	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/uhci.h	Mon Apr 24 16:15:01 2000
@@ -339,10 +339,10 @@
 
 	struct uhci_qh *qh;		/* QH for this URB */
 
-	int fsbr : 1;			/* Did this URB turn on FSBR? */
-	int queued : 1;			/* 0 if QH was linked in */
-
-	char short_control_packet;	/* If we get a short packet during */
+	int fsbr : 1;			/* URB turned on FSBR */
+	int fsbr_timeout : 1;		/* URB timed out on FSBR */
+	int queued : 1;			/* QH was queued (not linked in) */
+	int short_control_packet : 1;	/* If we get a short packet during */
 					/*  a control transfer, retrigger */
 					/*  the status phase */
 
@@ -414,6 +414,7 @@
 /* Debugging code */
 void uhci_show_td(struct uhci_td *td);
 void uhci_show_status(struct uhci *uhci);
+void uhci_show_urb_queue(struct urb *urb);
 void uhci_show_queue(struct uhci_qh *qh);
 void uhci_show_queues(struct uhci *uhci);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.99-pre5/linux/drivers/usb/usb-core.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/usb-core.c	Fri Apr 21 14:03:00 2000
@@ -28,6 +28,7 @@
  * USB device drivers
  */
 
+int usb_cpia_init(void);
 int usb_audio_init(void);
 int usb_ibmcam_init(void);
 int dabusb_init(void);
@@ -68,6 +69,9 @@
 	usb_hub_init();
 
 #ifndef CONFIG_USB_MODULE
+#ifdef CONFIG_VIDEO_CPIA_USB
+	usb_cpia_init();
+#endif
 #ifdef CONFIG_USB_AUDIO
 	usb_audio_init();
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.3.99-pre5/linux/drivers/usb/usb-ohci.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/usb-ohci.c	Wed Apr 26 15:22:55 2000
@@ -1555,7 +1555,7 @@
 					data_buf = root_hub_config_des; OK(len);
 				case (0x03): /* string descriptors */
 					len = usb_root_hub_string (wValue & 0xff,
-						(int) ohci->regs, "OHCI",
+						(int)(long) ohci->regs, "OHCI",
 						data, wLength);
 					if (len > 0) {
 						data_buf = data;
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c
--- v2.3.99-pre5/linux/drivers/usb/usb-storage.c	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/usb-storage.c	Fri Apr 21 14:03:00 2000
@@ -74,42 +74,50 @@
 
 	unsigned int		flags;		 /* from filter initially */
 
-	/* information about the device -- only good if device is attached */
-	__u8			ifnum;		 /* interface number */
-	__u8			ep_in;		 /* in endpoint */
-	__u8			ep_out;		 /* out ....... */
-	__u8			ep_int;		 /* interrupt . */
+	/* information about the device -- always good */
+	char                    vendor[32];
+	char                    product[32];
+	char                    serial[32];
+	char                    *transport_name;
+	char                    *protocol_name;
 	__u8			subclass;
 	__u8			protocol;
 
+	/* information about the device -- only good if device is attached */
+	__u8			ifnum;		 /* interface number   */
+	__u8			ep_in;		 /* bulk in endpoint   */
+	__u8			ep_out;		 /* bulk out endpoint  */
+	__u8			ep_int;		 /* interrupt endpoint */
+	__u8                    ep_interval;     /* interrupt interval */
+
 	/* function pointers for this device */
-	trans_cmnd              transport;	 /* transport function */
+	trans_cmnd              transport;	 /* transport function     */
 	trans_reset             transport_reset; /* transport device reset */
-	proto_cmnd              proto_handler;   /* protocol handler */
+	proto_cmnd              proto_handler;   /* protocol handler       */
 
 	/* SCSI interfaces */
-	GUID(guid);				 /* unique dev id */
+	GUID(guid);				 /* unique dev id       */
 	struct Scsi_Host	*host;		 /* our dummy host data */
-	Scsi_Host_Template	htmplt;  	 /* own host template */
-	int			host_number;	 /* to find us */
-	int			host_no;	 /* allocated by scsi */
-	Scsi_Cmnd		*srb;		 /* current srb */
+	Scsi_Host_Template	htmplt;  	 /* own host template   */
+	int			host_number;	 /* to find us          */
+	int			host_no;	 /* allocated by scsi   */
+	Scsi_Cmnd		*srb;		 /* current srb         */
 	
 	/* thread information */
 	Scsi_Cmnd		*queue_srb;	 /* the single queue slot */
-	int			action;		 /* what to do */
-	int			pid;		 /* control thread */
+	int			action;		 /* what to do            */
+	int			pid;		 /* control thread        */
 
-	/* interrupt info for CBI devices */
-	struct semaphore	ip_waitq;	 /* for CBI interrupts */
-	__u16			ip_data;	 /* interrupt data */
-	int			ip_wanted;	 /* needed */
+	/* interrupt info for CBI devices -- only good if attached */
+	struct semaphore	ip_waitq;	 /* for CBI interrupts   */
+	__u16			ip_data;	 /* interrupt data       */
+	int			ip_wanted;	 /* is an IRQ expected?  */
 	void			*irq_handle;	 /* for USB int requests */
 	unsigned int		irqpipe;	 /* pipe for release_irq */
 
 	/* mutual exclusion structures */
-	struct semaphore	notify;          /* thread begin/end */
-	struct semaphore        sleeper;         /* to sleep on */
+	struct semaphore	notify;          /* thread begin/end        */
+	struct semaphore        sleeper;         /* to sleep the thread on  */
 	struct semaphore        queue_exclusion; /* to protect data structs */
 };
 
@@ -118,11 +126,10 @@
  */
 
 #define US_ACT_COMMAND		1
-#define US_ACT_ABORT		2
-#define US_ACT_DEVICE_RESET	3
-#define US_ACT_BUS_RESET	4
-#define US_ACT_HOST_RESET	5
-#define US_ACT_EXIT		6
+#define US_ACT_DEVICE_RESET	2
+#define US_ACT_BUS_RESET	3
+#define US_ACT_HOST_RESET	4
+#define US_ACT_EXIT		5
 
 /* The list of structures and the protective lock for them */
 static struct us_data *us_list;
@@ -131,18 +138,15 @@
 static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
 static void storage_disconnect(struct usb_device *dev, void *ptr);
 static struct usb_driver storage_driver = {
-	"usb-storage",
-	storage_probe,
-	storage_disconnect,
-	{ NULL, NULL }
+	name:		"usb-storage",
+	probe:		storage_probe,
+	disconnect:	storage_disconnect,
 };
 
 /***********************************************************************
  * Data transfer routines
  ***********************************************************************/
 
-/* FIXME: the names of these functions are poorly choosen. */
-
 /*
  * Transfer one SCSI scatter-gather buffer via bulk transfer
  *
@@ -154,15 +158,15 @@
  * timeout limit.  Thus we don't have to worry about it for individual
  * packets.
  */
-static int us_bulk_transfer(struct us_data *us, int pipe, 
-			    char *buf, int length)
+static int us_transfer_partial(struct us_data *us, int pipe, 
+			       char *buf, int length)
 {
 	int result;
 	int partial;
 
 	/* transfer the data */
 	US_DEBUGP("Bulk xfer 0x%x(%d)\n", (unsigned int)buf, length);
-	result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ*5);
+	result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ);
 	US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
 		  result, partial, length);
 	
@@ -181,7 +185,7 @@
 	if (result) {
 		/* NAK - that means we've retried a few times allready */
 		if (result == -ETIMEDOUT) {
-			US_DEBUGP("us_bulk_transfer: device NAKed\n");
+			US_DEBUGP("us_transfer_partial(): device NAKed\n");
 		}
 		return US_BULK_TRANSFER_FAILED;
 	}
@@ -195,7 +199,7 @@
  * Transfer an entire SCSI command's worth of data payload over the bulk
  * pipe.
  *
- * Note that this uses us_bulk_transfer to achive it's goals -- this
+ * Note that this uses us_transfer_partial to achieve it's goals -- this
  * function simply determines if we're going to use scatter-gather or not,
  * and acts appropriately.  For now, it also re-interprets the error codes.
  */
@@ -222,16 +226,16 @@
 		 */
 		sg = (struct scatterlist *) srb->request_buffer;
 		for (i = 0; i < srb->use_sg; i++) {
-			result = us_bulk_transfer(us, pipe, sg[i].address, 
-						  sg[i].length);
+			result = us_transfer_partial(us, pipe, sg[i].address,
+						     sg[i].length);
 			if (result)
 				break;
 		}
 	}
 	else
 		/* no scatter-gather, just make the request */
-		result = us_bulk_transfer(us, pipe, srb->request_buffer, 
-					  srb->request_bufflen);
+		result = us_transfer_partial(us, pipe, srb->request_buffer,
+					     srb->request_bufflen);
 
 	/* return the result in the data structure itself */
 	srb->result = result;
@@ -240,12 +244,27 @@
 /* Calculate the length of the data transfer (not the command) for any
  * given SCSI command
  */
-static unsigned int us_transfer_length(Scsi_Cmnd *srb)
+static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
 {
 	int i;
 	unsigned int total = 0;
 	struct scatterlist *sg;
 
+	/* support those devices which need the length calculated
+	 * differently
+	 */
+	if (us->flags & US_FL_ALT_LENGTH) {
+		if (srb->cmnd[0] == INQUIRY) {
+			srb->cmnd[4] = 36;
+		}
+
+		if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
+			return srb->cmnd[4];
+
+		if (srb->cmnd[0] == TEST_UNIT_READY)
+			return 0;
+	}
+
 	/* Are we going to scatter gather? */
 	if (srb->use_sg) {
 		/* Add up the sizes of all the scatter-gather segments */
@@ -299,8 +318,10 @@
 		 */
 		if (us->subclass == US_SC_UFI &&
 		    ((srb->cmnd[0] == REQUEST_SENSE) ||
-		     (srb->cmnd[0] == INQUIRY)))
+		     (srb->cmnd[0] == INQUIRY))) {
+			US_DEBUGP("** no auto-sense for a special command\n");
 			need_auto_sense = 0;
+		}
 	}
 
 	/*
@@ -339,8 +360,13 @@
 		int temp_result;
 		void* old_request_buffer;
 		int old_sg;
+		int old_request_bufflen;
+		unsigned char old_cmnd[MAX_COMMAND_SIZE];
 
-		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
+
+		/* save the old command */
+		memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
 
 		srb->cmnd[0] = REQUEST_SENSE;
 		srb->cmnd[1] = 0;
@@ -351,14 +377,24 @@
     
 		/* set the buffer length for transfer */
 		old_request_buffer = srb->request_buffer;
+		old_request_bufflen = srb->request_bufflen;
 	        old_sg = srb->use_sg;
+		srb->use_sg = 0;
 		srb->request_bufflen = 18;
-		srb->request_buffer = us->srb->sense_buffer;
+		srb->request_buffer = srb->sense_buffer;
 
-		/* FIXME: what if this command fails? */
+		/* issue the auto-sense command */
 		temp_result = us->transport(us->srb, us);
+		if (temp_result == USB_STOR_TRANSPORT_ERROR) {
+			/* FIXME: we need to invoke a transport reset here */
+			US_DEBUGP("-- auto-sense failure\n");
+			srb->result = DID_ERROR << 16;
+			return;
+		}
+
 		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+		US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+			  srb->sense_buffer[0],
 			  srb->sense_buffer[2] & 0xf,
 			  srb->sense_buffer[12], 
 			  srb->sense_buffer[13]);
@@ -366,16 +402,32 @@
 		/* set the result so the higher layers expect this data */
 		srb->result = CHECK_CONDITION;
 
-		/* we're done here */
+		/* we're done here, let's clean up */
 		srb->request_buffer = old_request_buffer;
+		srb->request_bufflen = old_request_bufflen;
 		srb->use_sg = old_sg;
-	}
+		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
 
-	/* Set return code, if necessary */
-	if (need_auto_sense && (srb->sense_buffer[0] == 0x0))
-		srb->result = GOOD;
-	if (!need_auto_sense)
+		/* If things are really okay, then let's show that */
+		if ((srb->sense_buffer[2] & 0xf) == 0x0)
+			srb->result = GOOD;
+	} else /* if (need_auto_sense) */
 		srb->result = GOOD;
+
+	/* Regardless of auto-sense, if we _know_ we have an error
+	 * condition, show that in the result code
+	 */
+	if (result == USB_STOR_TRANSPORT_FAILED)
+		srb->result = CHECK_CONDITION;
+
+	/* If we think we're good, then make sure the sense data shows it.
+	 * This is necessary because the auto-sense for some devices always
+	 * sets byte 0 == 0x70, even if there is no error
+	 */
+	if ((us->protocol == US_PR_CB) && 
+	    (result == USB_STOR_TRANSPORT_GOOD) &&
+	    ((srb->sense_buffer[2] & 0xf) == 0x0))
+		srb->sense_buffer[0] = 0x0;
 }
 
 /*
@@ -444,7 +496,7 @@
 
 	/* DATA STAGE */
 	/* transfer the data payload for this command, if one exists*/
-	if (us_transfer_length(srb)) {
+	if (us_transfer_length(srb, us)) {
 		us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
 		US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
 	}
@@ -454,7 +506,7 @@
 	/* go to sleep until we get this interrupt */
 	down(&(us->ip_waitq));
 	
-	/* if we were woken up by a reset instead of the actual interrupt */
+	/* if we were woken up by an abort instead of the actual interrupt */
 	if (us->ip_wanted) {
 		US_DEBUGP("Did not get interrupt on CBI\n");
 		us->ip_wanted = 0;
@@ -532,7 +584,7 @@
 
 	/* DATA STAGE */
 	/* transfer the data payload for this command, if one exists*/
-	if (us_transfer_length(srb)) {
+	if (us_transfer_length(srb, us)) {
 		us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
 		US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
 	}
@@ -558,7 +610,7 @@
 	
 	/* set up the command wrapper */
 	bcb.Signature = US_BULK_CB_SIGN;
-	bcb.DataTransferLength = us_transfer_length(srb);
+	bcb.DataTransferLength = us_transfer_length(srb, us);
 	bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
 	bcb.Tag = srb->serial_number;
 	bcb.Lun = srb->cmnd[1] >> 5;
@@ -603,27 +655,31 @@
 	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
 	
 	/* get CSW for device status */
+	US_DEBUGP("Attempting to get CSW...\n");
 	result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
-			      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+			      US_BULK_CS_WRAP_LEN, &partial, HZ);
 	
 	/* did the attempt to read the CSW fail? */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
 		usb_clear_halt(us->pusb_dev, pipe);
-		
+
 		/* get the status again */
+		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
 		result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
-				      US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+				      US_BULK_CS_WRAP_LEN, &partial, HZ);
 		
 		/* if it fails again, we need a reset and return an error*/
 		if (result == -EPIPE) {
+			US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
+			usb_clear_halt(us->pusb_dev, pipe);
 			return USB_STOR_TRANSPORT_ERROR;
 		}
 	}
 	
 	/* if we still have a failure at this point, we're in trouble */
+	US_DEBUGP("Bulk status result = %d\n", result);
 	if (result) {
-		US_DEBUGP("Bulk status result = %d\n", result);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 	
@@ -1120,14 +1176,14 @@
 	printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
 	US_DEBUGP("Bus reset requested\n");
 	//  us->transport_reset(us);
-	return SUCCESS;
+	return FAILED;
 }
 
 /* FIXME: This doesn't actually reset anything */
 static int us_host_reset( Scsi_Cmnd *srb )
 {
 	printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
-	return 0;
+	return FAILED;
 }
 
 /***********************************************************************
@@ -1136,14 +1192,14 @@
 
 /* we use this macro to help us write into the buffer */
 #undef SPRINTF
-#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0)
+#define SPRINTF(args...) \
+	do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
 
 int usb_stor_proc_info (char *buffer, char **start, off_t offset, 
 			int length, int hostno, int inout)
 {
 	struct us_data *us;
 	char *pos = buffer;
-	char *tmp_ptr;
 
 	/* if someone is sending us data, just throw it away */
 	if (inout)
@@ -1167,80 +1223,19 @@
 	}
 	
 	/* print the controler name */
-	SPRINTF ("Host scsi%d: usb-storage\n", hostno);
+	SPRINTF("   Host scsi%d: usb-storage\n", hostno);
 
-	/* print product and vendor strings */
-	tmp_ptr = kmalloc(256, GFP_KERNEL);
-	if (!us->pusb_dev || !tmp_ptr) {
-		SPRINTF("    Vendor: Unknown Vendor\n");
-		SPRINTF("   Product: Unknown Product\n");
-	} else {
-		SPRINTF("    Vendor: ");
-		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0)
-			SPRINTF("%s\n", tmp_ptr);
-		else
-			SPRINTF("Unknown Vendor\n");
-    
-		SPRINTF("   Product: ");
-		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0)
-			SPRINTF("%s\n", tmp_ptr);
-		else
-			SPRINTF("Unknown Product\n");
-		kfree(tmp_ptr);
-	}
-
-	SPRINTF("  Protocol: ");
-	switch (us->protocol) {
-	case US_PR_CB:
-		SPRINTF("Control/Bulk\n");
-		break;
-    
-	case US_PR_CBI:
-		SPRINTF("Control/Bulk/Interrupt\n");
-		break;
-    
-	case US_PR_BULK:
-		SPRINTF("Bulk only\n");
-		break;
-    
-	default:
-		SPRINTF("Unknown Protocol\n");
-		break;
-	}
-
-	SPRINTF(" Transport: ");
-	switch (us->subclass) {
-	case US_SC_RBC:
-		SPRINTF("Reduced Block Commands\n");
-		break;
-
-	case US_SC_8020:
-		SPRINTF("8020i\n");
-		break;
-
-	case US_SC_QIC:
-		SPRINTF("QIC-157\n");
-		break;
-    
-	case US_SC_8070:
-		SPRINTF("8070i\n");
-		break;
-
-	case US_SC_SCSI:
-		SPRINTF("Transparent SCSI\n");
-		break;
-    
-	case US_SC_UFI:
-		SPRINTF("Uniform Floppy Interface\n");
-		break;
-    
-	default:
-		SPRINTF("Unknown Transport\n");
-		break;
-	}
+	/* print product, vendor, and serial number strings */
+	SPRINTF("       Vendor: %s\n", us->vendor);
+	SPRINTF("      Product: %s\n", us->product);
+	SPRINTF("Serial Number: %s\n", us->serial);
+
+	/* show the protocol and transport */
+	SPRINTF("     Protocol: %s\n", us->protocol_name);
+	SPRINTF("    Transport: %s\n", us->transport_name);
 
 	/* show the GUID of the device */
-	SPRINTF("      GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
+	SPRINTF("         GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
 
 	/* release our lock on the data structures */
 	up(&us_list_semaphore);
@@ -1263,30 +1258,30 @@
  */
 
 static Scsi_Host_Template my_host_template = {
-	name:           "usb-storage",
-	proc_info:	usb_stor_proc_info,
-	info:           us_info,
-
-	detect:		us_detect,
-	release:	us_release,
-	command:	us_command,
-	queuecommand:	us_queuecommand,
+	name:			"usb-storage",
+	proc_info:		usb_stor_proc_info,
+	info:			us_info,
+
+	detect:			us_detect,
+	release:		us_release,
+	command:		us_command,
+	queuecommand:		us_queuecommand,
 
 	eh_abort_handler:	us_abort,
 	eh_device_reset_handler:us_bus_reset,
 	eh_bus_reset_handler:	us_bus_reset,
 	eh_host_reset_handler:	us_host_reset,
 
-	can_queue:	1,
-	this_id:	-1,
+	can_queue:		1,
+	this_id:		-1,
 
-	sg_tablesize:	   SG_ALL,
-	cmd_per_lun:	   1,
-	present:	   0,
-	unchecked_isa_dma: FALSE,
-	use_clustering:	   TRUE,
-	use_new_eh_code:   TRUE,
-	emulated:	   TRUE,
+	sg_tablesize:		SG_ALL,
+	cmd_per_lun:		1,
+	present:		0,
+	unchecked_isa_dma:	FALSE,
+	use_clustering:		TRUE,
+	use_new_eh_code:	TRUE,
+	emulated:		TRUE
 };
 
 static unsigned char sense_notready[] = {
@@ -1321,6 +1316,7 @@
 	 */
 	daemonize();
 
+	/* set our name for identification purposes */
 	sprintf(current->comm, "usb-storage-%d", us->host_number);
 
 	unlock_kernel();
@@ -1334,7 +1330,7 @@
 		down(&(us->queue_exclusion));
 		US_DEBUGP("*** thread awakened.\n");
 
-				/* take the command off the queue */
+		/* take the command off the queue */
 		action = us->action;
 		us->action = 0;
 		us->srb = us->queue_srb;
@@ -1344,10 +1340,14 @@
 
 		switch (action) {
 		case US_ACT_COMMAND:
-			/* bad device */
-			if (us->srb->target) {
-				US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
-					   us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
+			/* reject if target != 0 or if single-lun device
+			 * and LUN != 0
+			 */
+			if (us->srb->target ||
+			    ((us->flags & US_FL_SINGLE_LUN) && us->srb->lun)) {
+				US_DEBUGP("Bad device number (%d/%d)\n",
+					  us->srb->target, us->srb->lun);
+
 				us->srb->result = DID_BAD_TARGET << 16;
 
 				us->srb->scsi_done(us->srb);
@@ -1355,59 +1355,51 @@
 				break;
 			}
 
+			/* handle those devices which can't do a START_STOP */
+			if ((us->srb->cmnd[0] == START_STOP) &&
+			    (us->flags & US_FL_START_STOP)) {
+				us->srb->result = GOOD;
+				us->srb->scsi_done(us->srb);
+				us->srb = NULL;
+				break;
+			}
+				     
 			/* lock the device pointers */
 			down(&(us->dev_semaphore));
 
 			/* our device has gone - pretend not ready */
-			/* FIXME: we also need to handle INQUIRY here, 
-			 * probably */
-			/* FIXME: fix return codes and sense buffer handling */
 			if (!us->pusb_dev) {
 				US_DEBUGP("Request is for removed device\n");
+				/* For REQUEST_SENSE, it's the data.  But
+				 * for anything else, it should look like
+				 * we auto-sensed for it.
+				 */
 				if (us->srb->cmnd[0] == REQUEST_SENSE) {
 					memcpy(us->srb->request_buffer, 
 					       sense_notready, 
 					       sizeof(sense_notready));
-					us->srb->result = DID_OK << 16;
+					us->srb->result = GOOD;
 				} else {
-					us->srb->result = (DID_OK << 16) | 2;
+					memcpy(us->srb->sense_buffer,
+					       sense_notready,
+					       sizeof(sense_notready));
+					us->srb->result = CHECK_CONDITION;
 				}
-
-				/* unlock the device pointers */
-				up(&(us->dev_semaphore));
-
-				/* indicate that the command is done */
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				break;
-			}
-
-			/* we've got a command, let's do it! */
-			US_DEBUG(us_show_command(us->srb));
-
-			/* FIXME: this is to support Shuttle E-USB bridges, it 
-			 * appears */
-			if (us->srb->cmnd[0] == START_STOP &&
-			    us->pusb_dev->descriptor.idProduct == 0x0001 &&
-			    us->pusb_dev->descriptor.idVendor == 0x04e6)
-				us->srb->result = DID_OK << 16;
-			else {
+			} else { /* !us->pusb_dev */
+				/* we've got a command, let's do it! */
+				US_DEBUG(us_show_command(us->srb));
 				us->proto_handler(us->srb, us);
 			}
-      
-			US_DEBUGP("scsi cmd done, result=0x%x\n", 
-				  us->srb->result);
 
 			/* unlock the device pointers */
 			up(&(us->dev_semaphore));
 
 			/* indicate that the command is done */
+			US_DEBUGP("scsi cmd done, result=0x%x\n",
+				  us->srb->result);
 			us->srb->scsi_done(us->srb);
 			us->srb = NULL;
 			break;
-      
-		case US_ACT_ABORT:
-			break;
 
 		case US_ACT_DEVICE_RESET:
 			break;
@@ -1426,22 +1418,71 @@
 			break;
 		}
 	} /* for (;;) */
-  
+
 	/* notify the exit routine that we're actually exiting now */
 	up(&(us->notify));
 
 	return 0;
 }	
 
+static struct us_unusual_dev us_unusual_dev_list[] = {
+	{ 0x057b, 0x0000, 0x0114,
+	  "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN },
+	{ 0x0781, 0x0001, 0x0200,
+	  "Sandisk ImageMate", US_SC_SCSI, US_PR_CB, 
+	  US_FL_SINGLE_LUN | US_FL_START_STOP },
+	{ 0x0781, 0x0002, 0x0009,
+	  "** SECRET DEVICE **", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN },
+	{ 0x04e6, 0x0002, 0x0100,
+	  "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+	{ 0x07af, 0x0005, 0x0100,
+	  "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+	{ 0x0000, 0x0000, 0x0,
+	  "", 0, 0, 0}
+};
+
+/* Search our ususual device list, based on vendor/product combinations
+ * to see if we can support this device.  Returns a pointer to a structure
+ * defining how we should support this device, or NULL if it's not in the
+ * list
+ */
+static struct us_unusual_dev* us_find_dev(__u16 idVendor, __u16 idProduct, 
+					  __u16 bcdDevice)
+{
+	struct us_unusual_dev* ptr;
+
+	US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n",
+		  idVendor, idProduct, bcdDevice);
+
+	ptr = us_unusual_dev_list;
+	while ((ptr->idVendor != 0x0000) && 
+	       !((ptr->idVendor == idVendor) && 
+		 (ptr->idProduct == idProduct) &&
+		 (ptr->bcdDevice == bcdDevice)))
+		ptr++;
+	
+	/* if the search ended because we hit the end record, we failed */
+	if (ptr->idVendor == 0x0000) {
+		US_DEBUGP("-- did not find a matching device\n");
+		return NULL;
+	}
+
+	/* otherwise, we found one! */
+	US_DEBUGP("-- found matching device: %s\n", ptr->name);
+	return ptr;
+}
+
 /* Probe to see if a new device is actually a SCSI device */
 static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	int i;
-	char mf[32];		     /* manufacturer */
-	char prod[32];		     /* product */
-	char serial[32];       	     /* serial number */
+	char mf[USB_STOR_STRING_LEN];		     /* manufacturer */
+	char prod[USB_STOR_STRING_LEN];		     /* product */
+	char serial[USB_STOR_STRING_LEN];      	     /* serial number */
+	GUID(guid);		           /* Global Unique Identifier */
+	unsigned int flags;
+	struct us_unusual_dev *unusual_dev;
 	struct us_data *ss = NULL;
-	GUID(guid);		     /* Global Unique Identifier */
 	int result;
 
 	/* these are temporary copies -- we test on these, then put them
@@ -1450,6 +1491,7 @@
 	__u8 ep_in = 0;
 	__u8 ep_out = 0;
 	__u8 ep_int = 0;
+	__u8 ep_interval = 0;
 	__u8 subclass = 0;
 	__u8 protocol = 0;
 
@@ -1457,10 +1499,22 @@
 	struct usb_interface_descriptor *altsetting = 
 		&(dev->actconfig->interface[ifnum].altsetting[0]); 
 
-	/* FIXME: this isn't quite right... */
-	/* We make an exception for the shuttle E-USB */
-	if (!(dev->descriptor.idVendor == 0x04e6 &&
-	      dev->descriptor.idProduct == 0x0001) &&
+	/* clear the temporary strings */
+	memset(mf, 0, sizeof(mf));
+	memset(prod, 0, sizeof(prod));
+	memset(serial, 0, sizeof(serial));
+
+	/* search for this device in our unusual device list */
+	unusual_dev = us_find_dev(dev->descriptor.idVendor, 
+				  dev->descriptor.idProduct,
+				  dev->descriptor.bcdDevice);
+
+	/* 
+	 * Can we support this device, either because we know about it
+	 * from our unusual device list, or because it advertises that it's
+	 * compliant to the specification?
+	 */
+	if (!unusual_dev &&
 	    !(dev->descriptor.bDeviceClass == 0 &&
 	      altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
 	      altsetting->bInterfaceSubClass >= US_SC_MIN &&
@@ -1473,37 +1527,16 @@
 	US_DEBUGP("USB Mass Storage device detected\n");
 
 	/* Determine subclass and protocol, or copy from the interface */
-	/* FIXME: this isn't quite right */
-	if (dev->descriptor.idVendor == 0x04e6 &&
-	    dev->descriptor.idProduct == 0x0001) {
-		protocol = US_PR_CB;
-		subclass = US_SC_8070;	    /* an assumption */
+	if (unusual_dev) {
+		subclass = unusual_dev->useProtocol;
+		protocol = unusual_dev->useTransport;
+		flags = unusual_dev->flags;
 	} else {
 		subclass = altsetting->bInterfaceSubClass;
 		protocol = altsetting->bInterfaceProtocol;
+		flags = 0;
 	}
-
-	/* shuttle E-USB */	
-	/* FIXME: all we should need to do here is determine the protocol */
-	if (dev->descriptor.idVendor == 0x04e6 &&
-	    dev->descriptor.idProduct == 0x0001) {
-		__u8 qstat[2];
-		
-		result = usb_control_msg(ss->pusb_dev, 
-					 usb_rcvctrlpipe(dev,0),
-					 1, 0xC0,
-					 0, ss->ifnum,
-					 qstat, 2, HZ*5);
-		US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
-		init_MUTEX_LOCKED(&(ss->ip_waitq));
-		ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
-		result = usb_request_irq(ss->pusb_dev, ss->irqpipe, 
-					 CBI_irq, 255, (void *)ss, 
-					 &ss->irq_handle);
-		if (result < 0)
-			return NULL;
-	}
-			
+	
 	/*
 	 * Find the endpoints we need
 	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
@@ -1529,10 +1562,11 @@
 		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
 			ep_int = altsetting->endpoint[i].bEndpointAddress &
 				USB_ENDPOINT_NUMBER_MASK;
+			ep_interval = altsetting->endpoint[i].bInterval;
 		}
 	}
-	US_DEBUGP("Endpoints In %d Out %d Int %d\n",
-		  ep_in, ep_out, ep_int);
+	US_DEBUGP("Endpoints: In %d Out %d Int %d (Period %d)\n",
+		  ep_in, ep_out, ep_int, ep_interval);
 
 	/* set the interface -- STALL is an acceptable response here */
 	result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
@@ -1542,13 +1576,13 @@
 		usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
 	} else if (result != 0) {
 		/* it's not a stall, but another error -- time to bail */
-		US_DEBUGP("-- unknown error.  rejecting device\n");
+		US_DEBUGP("-- Unknown error.  Rejecting device\n");
 		return NULL;
 	}
 
 	/* Do some basic sanity checks, and bail if we find a problem */
 	if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
-		US_DEBUGP("Problems with device\n");
+		US_DEBUGP("Sanity check failed.  Rejecting device.\n");
 		return NULL;
 	}
 
@@ -1556,9 +1590,6 @@
 
 	/* clear the GUID and fetch the strings */
 	GUID_CLEAR(guid);
-	memset(mf, 0, sizeof(mf));
-	memset(prod, 0, sizeof(prod));
-	memset(serial, 0, sizeof(serial));
 	if (dev->descriptor.iManufacturer)
 		usb_string(dev, dev->descriptor.iManufacturer, mf, 
 			   sizeof(mf));
@@ -1608,13 +1639,13 @@
 			init_MUTEX_LOCKED(&(ss->ip_waitq));
 			
 			/* set up the IRQ pipe and handler */
-			/* FIXME: This needs to get period from the device */
 			US_DEBUGP("Allocating IRQ for CBI transport\n");
 			ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
 			result = usb_request_irq(ss->pusb_dev, ss->irqpipe, 
-						 CBI_irq, 255, (void *)ss, 
+						 CBI_irq, ss->ep_interval,
+						 (void *)ss,
 						 &(ss->irq_handle));
-			US_DEBUGP("usb_request_irq returned %d\n", result);
+			US_DEBUGP("-- usb_request_irq returned %d\n", result);
 		}
 	} else { 
 		/* New device -- Allocate memory and initialize */
@@ -1637,16 +1668,29 @@
 		/* copy over the subclass and protocol data */
 		ss->subclass = subclass;
 		ss->protocol = protocol;
+		ss->flags = flags;
 
 		/* copy over the endpoint data */
 		ss->ep_in = ep_in;
 		ss->ep_out = ep_out;
 		ss->ep_int = ep_int;
+		ss->ep_interval = ep_interval;
 
 		/* establish the connection to the new device */
 		ss->ifnum = ifnum;
 		ss->pusb_dev = dev;
 
+		/* copy over the identifiying strings */
+		strncpy(ss->vendor, mf, USB_STOR_STRING_LEN);
+		strncpy(ss->product, prod, USB_STOR_STRING_LEN);
+		strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
+		if (strlen(ss->vendor) == 0)
+			strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN);
+		if (strlen(ss->product) == 0)
+			strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN);
+		if (strlen(ss->serial) == 0)
+			strncpy(ss->serial, "None", USB_STOR_STRING_LEN);
+
 		/* copy the GUID we created before */
 		memcpy(ss->guid, guid, sizeof(guid));
 		
@@ -1654,81 +1698,91 @@
 		 * Set the handler pointers based on the protocol
 		 * Again, this data is persistant across reattachments
 		 */
-		US_DEBUGP("Transport: ");
 		switch (ss->protocol) {
 		case US_PR_CB:
-			US_DEBUGPX("Control/Bulk\n");
+			ss->transport_name = "Control/Bulk";
 			ss->transport = CB_transport;
 			ss->transport_reset = CB_reset;
 			break;
 			
 		case US_PR_CBI:
-			US_DEBUGPX("Control/Bulk/Interrupt\n");
+			ss->transport_name = "Control/Bulk/Interrupt";
 			ss->transport = CBI_transport;
 			ss->transport_reset = CB_reset;
 			break;
 			
 		case US_PR_BULK:
-			US_DEBUGPX("Bulk\n");
+			ss->transport_name = "Bulk";
 			ss->transport = Bulk_transport;
 			ss->transport_reset = Bulk_reset;
 			break;
 			
 		default:
-			US_DEBUGPX("Unknown\n");    
+			ss->transport_name = "Unknown";
+			up(&us_list_semaphore);
 			kfree(ss);
 			return NULL;
 			break;
 		}
+		US_DEBUGP("Transport: %s\n", ss->transport_name);
 
-		US_DEBUGP("Protocol: ");
 		switch (ss->subclass) {
 		case US_SC_RBC:
-			US_DEBUGPX("Reduced Block Commands (RBC)\n");
+			ss->protocol_name = "Reduced Block Commands (RBC)";
 			ss->proto_handler = transparent_scsi_command;
 			break;
 
 		case US_SC_8020:
-			US_DEBUGPX("8020i\n");
+			ss->protocol_name = "8020i";
 			ss->proto_handler = ATAPI_command;
 			break;
 
 		case US_SC_QIC:
-			US_DEBUGPX("QIC-157\n");
+			ss->protocol_name = "QIC-157";
+			US_DEBUGP("Sorry, device not supported.  Please\n");
+			US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
+			US_DEBUGP("if you see this message.\n");
+			up(&us_list_semaphore);
+			kfree(ss);
+			return NULL;
 			break;
 
 		case US_SC_8070:
-			US_DEBUGPX("8070i\n");
+			ss->protocol_name = "8070i";
 			ss->proto_handler = ATAPI_command;
 			break;
 
 		case US_SC_SCSI:
-			US_DEBUGPX("Transparent SCSI\n");
+			ss->protocol_name = "Transparent SCSI";
 			ss->proto_handler = transparent_scsi_command;
 			break;
 
 		case US_SC_UFI:
-			US_DEBUGPX("UFI\n");
+			ss->protocol_name = "Uniform Floppy Interface (UFI)";
 			ss->proto_handler = ufi_command;
 			break;
 
 		default:
-			US_DEBUGPX("Unknown\n");
+			ss->protocol_name = "Unknown";
+			up(&us_list_semaphore);
+			kfree(ss);
+			return NULL;
 			break;
 		}
+		US_DEBUGP("Protocol: %s\n", ss->protocol_name);
 
 		if (ss->protocol == US_PR_CBI) {
 			/* set up so we'll wait for notification */
 			init_MUTEX_LOCKED(&(ss->ip_waitq));
 			
 			/* set up the IRQ pipe and handler */
-			/* FIXME: This needs to get period from the device */
 			US_DEBUGP("Allocating IRQ for CBI transport\n");
 			ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
 			result = usb_request_irq(ss->pusb_dev, ss->irqpipe, 
-						 CBI_irq, 255, (void *)ss,
+						 CBI_irq, ss->ep_interval,
+						 (void *)ss,
 						 &(ss->irq_handle));
-			US_DEBUGP("usb_request_irq returned %d\n", result);
+			US_DEBUGP("-- usb_request_irq returned %d\n", result);
 		}
 		
 		/*
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-storage.h linux/drivers/usb/usb-storage.h
--- v2.3.99-pre5/linux/drivers/usb/usb-storage.h	Tue Apr 11 15:09:20 2000
+++ linux/drivers/usb/usb-storage.h	Fri Apr 21 14:03:01 2000
@@ -7,7 +7,8 @@
 
 #include <linux/config.h>
 
-#define USB_STORAGE "usb-storage: "
+#define USB_STORAGE "usb-storage.c: "
+#define USB_STOR_STRING_LEN 32
 
 #ifdef CONFIG_USB_STORAGE_DEBUG
 void us_show_command(Scsi_Cmnd *srb);
@@ -128,9 +129,27 @@
 	}
 }
 
+/*
+ * Unusual device list definitions 
+ */
+
+struct us_unusual_dev {
+	/* we search the list based on these parameters */
+	__u16 idVendor;
+	__u16 idProduct;
+	__u16 bcdDevice;
+
+	/* the list specifies these parameters */
+	const char* name;
+	__u8  useProtocol;
+	__u8  useTransport;
+	unsigned int flags;
+};
+
 /* Flag definitions */
-#define US_FL_IP_STATUS	      0x00000001 /* status uses interrupt           */
-#define US_FL_FIXED_COMMAND   0x00000002 /* expand commands to fixed size   */
-#define US_FL_MODE_XLATE      0x00000004 /* translate _6 to _10 comands for
+#define US_FL_SINGLE_LUN      0x00000001 /* allow access to only LUN 0 */
+#define US_FL_MODE_XLATE      0x00000002 /* translate _6 to _10 comands for
 					            Win/MacOS compatibility */
-#define US_FL_CBI_AS_CB       0x00000008 /* treat a CBI dev as a CB dev     */
+#define US_FL_START_STOP      0x00000004 /* ignore START_STOP commands */
+#define US_FL_ALT_LENGTH      0x00000008 /* use the alternate algorithm for
+                                                    us_transfer_length() */
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.99-pre5/linux/drivers/video/Config.in	Tue Apr 11 15:09:21 2000
+++ linux/drivers/video/Config.in	Mon Apr 24 13:49:18 2000
@@ -118,7 +118,7 @@
 	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
 	 fi
 	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
-	 bool '  ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
+	 tristate '  ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
 	 bool '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
       fi
    fi
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- v2.3.99-pre5/linux/drivers/video/acornfb.c	Thu Feb 10 17:11:15 2000
+++ linux/drivers/video/acornfb.c	Tue Apr 25 17:38:33 2000
@@ -1599,7 +1599,7 @@
 	}
 
 	current_par.currcon	   = -1;
-	current_par.screen_base	   = SCREEN2_BASE;
+	current_par.screen_base	   = SCREEN_BASE;
 	current_par.screen_base_p  = SCREEN_START;
 	current_par.using_vram     = 0;
 
@@ -1696,7 +1696,8 @@
 	v_sync = h_sync / (init_var.yres + init_var.upper_margin +
 		 init_var.lower_margin + init_var.vsync_len);
 
-	printk("Acornfb: %ldkB %cRAM, %s, using %dx%d, %d.%03dkHz, %dHz\n",
+	printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, "
+		"%d.%03dkHz, %dHz\n",
 		current_par.screen_size / 1024,
 		current_par.using_vram ? 'V' : 'D',
 		VIDC_NAME, init_var.xres, init_var.yres,
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.99-pre5/linux/drivers/video/aty128fb.c	Tue Apr 11 15:09:21 2000
+++ linux/drivers/video/aty128fb.c	Mon Apr 24 13:49:18 2000
@@ -180,7 +180,7 @@
 #ifndef MODULE
 static const char *mode_option __initdata = NULL;
 #endif
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
 static void *bios_seg = NULL;
 #endif
 
@@ -244,12 +244,13 @@
     struct fb_info fb_info;
     struct fb_info_aty128 *next;
     struct aty128_constants constants;  /* PLL and others      */
-    unsigned long regbase_phys;         /* physical mmio       */
+    u32 regbase_phys;                   /* physical mmio       */
     void *regbase;                      /* remapped mmio       */
-    unsigned long frame_buffer_phys;    /* physical fb memory  */
-    unsigned long frame_buffer;         /* remaped framebuffer */
-    const struct aty128_meminfo *mem;   /* onboard mem info    */
+    u32 frame_buffer_phys;              /* physical fb memory  */
+    u32 frame_buffer;                   /* remaped framebuffer */
+    u32 io_base;                        /* unmapped io         */
     u32 vram_size;                      /* onboard video ram   */
+    const struct aty128_meminfo *mem;   /* onboard mem info    */
     struct aty128fb_par default_par, current_par;
     struct display disp;
     struct display_switch dispsw;       /* for cursor and font */
@@ -301,6 +302,7 @@
 			   struct fb_info *fb);
 static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		     u_long arg, int con, struct fb_info *info);
+static int aty128fb_rasterimg(struct fb_info *info, int start);
 
 
     /*
@@ -308,8 +310,8 @@
      */
 
 int aty128fb_init(void);
-static int aty128fbcon_switch(int con, struct fb_info *info);
-static void aty128fbcon_blank(int blank, struct fb_info *info);
+static int aty128fbcon_switch(int con, struct fb_info *fb);
+static void aty128fbcon_blank(int blank, struct fb_info *fb);
 
     /*
      *  Internal routines
@@ -335,9 +337,9 @@
                                const struct aty128_chip_info *aci);
 static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128
 				*board_list, struct fb_info_aty128 *new_node);
-static int aty128find_ROM(struct fb_info_aty128 *info);
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
 static void aty128_get_pllinfo(struct fb_info_aty128 *info);
+static int aty128find_ROM(struct fb_info_aty128 *info);
 #endif
 static void aty128_timings(struct fb_info_aty128 *info);
 static void aty128_init_engine(const struct aty128fb_par *par, 
@@ -385,29 +387,26 @@
 static struct fb_ops aty128fb_ops = {
     aty128fb_open, aty128fb_release, aty128fb_get_fix,
     aty128fb_get_var, aty128fb_set_var, aty128fb_get_cmap,
-    aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl
+    aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl,
+    NULL, aty128fb_rasterimg
 };
 
 
     /*
      * Functions to read from/write to the mmio registers
-     *	- endian conversions may possibly be avoided by flipping CONFIG_CNTL
-     *  or using the other register aperture? TODO.
+     *	- endian conversions may possibly be avoided by
+     *    using the other register aperture. TODO.
      */
 static inline u32
 _aty_ld_le32(volatile unsigned int regindex, 
                               const struct fb_info_aty128 *info)
 {
-    unsigned long *temp;
     u32 val;
 
 #if defined(__powerpc__)
-    eieio();
-    temp = info->regbase;
-    asm("lwbrx %0,%1,%2" : "=b"(val) : "b" (regindex), "b" (temp));
+    asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(info->regbase));
 #else
-    temp = info->regbase+regindex;
-    val = readl (temp);
+    val = readl (info->regbase + regindex);
 #endif
 
     return val;
@@ -417,35 +416,23 @@
 _aty_st_le32(volatile unsigned int regindex, u32 val, 
                                const struct fb_info_aty128 *info)
 {
-    unsigned long *temp;
-
 #if defined(__powerpc__)
-    temp = info->regbase;
-    asm("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r" (temp) :
-        "memory");
-#elif defined(__mc68000__)
-    *((volatile u32 *)(info->regbase+regindex)) = cpu_to_le32(val);
+    asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex),
+                "r"(info->regbase) : "memory");
 #else
-    temp = info->regbase+regindex;
-    writel (val, temp);
+    writel (val, info->regbase + regindex);
 #endif
 }
 
 static inline u8
 _aty_ld_8(unsigned int regindex, const struct fb_info_aty128 *info)
 {
-#if defined(__powerpc__)
-    eieio();
-#endif
     return readb (info->regbase + regindex);
 }
 
 static inline void
 _aty_st_8(unsigned int regindex, u8 val, const struct fb_info_aty128 *info)
 {
-#if defined(__powerpc__)
-    eieio();
-#endif
     writeb (val, info->regbase + regindex);
 }
 
@@ -466,9 +453,6 @@
 _aty_ld_pll(unsigned int pll_index,
 			const struct fb_info_aty128 *info)
 {       
-#if defined(__powerpc__)
-    eieio();
-#endif
     aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F);
     return aty_ld_le32(CLOCK_CNTL_DATA);
 }
@@ -478,9 +462,6 @@
 _aty_st_pll(unsigned int pll_index, u32 val,
 			const struct fb_info_aty128 *info)
 {
-#if defined(__powerpc__)
-    eieio();
-#endif
     aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN);
     aty_st_le32(CLOCK_CNTL_DATA, val);
 }
@@ -528,7 +509,8 @@
 static int __init
 register_test(const struct fb_info_aty128 *info)
 {
-    u32 val, flag = 0;
+    u32 val;
+    int flag = 0;
 
     val = aty_ld_le32(BIOS_0_SCRATCH);
 
@@ -648,35 +630,34 @@
     u32 pitch_value;
 
     /* 3D scaler not spoken here */
+    wait_for_fifo(1, info);
     aty_st_le32(SCALE_3D_CNTL, 0x00000000);
 
     aty128_reset_engine(info);
 
-    pitch_value = par->crtc.pitch;	/* fix this up */
+    pitch_value = par->crtc.pitch;
     if (par->crtc.bpp == 24) {
         pitch_value = pitch_value * 3;
     }
 
+    wait_for_fifo(4, info);
     /* setup engine offset registers */
-    wait_for_fifo(1, info);
     aty_st_le32(DEFAULT_OFFSET, 0x00000000);
 
     /* setup engine pitch registers */
     aty_st_le32(DEFAULT_PITCH, pitch_value);
 
     /* set the default scissor register to max dimensions */
-    wait_for_fifo(1, info);
     aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF);
 
     /* set the drawing controls registers */
-    wait_for_fifo(1, info);
     aty_st_le32(DP_GUI_MASTER_CNTL,
 		GMC_SRC_PITCH_OFFSET_DEFAULT		|
 		GMC_DST_PITCH_OFFSET_DEFAULT		|
 		GMC_SRC_CLIP_DEFAULT			|
 		GMC_DST_CLIP_DEFAULT			|
 		GMC_BRUSH_SOLIDCOLOR			|
-		(bpp_to_depth(par->crtc.bpp << 8))	|
+		(bpp_to_depth(par->crtc.bpp) << 8)	|
 		GMC_SRC_DSTCOLOR			|
 		GMC_BYTE_ORDER_MSB_TO_LSB		|
 		GMC_DP_CONVERSION_TEMP_6500		|
@@ -688,7 +669,6 @@
 		GMC_WRITE_MASK_SET);
 
     wait_for_fifo(8, info);
-
     /* clear the line drawing registers */
     aty_st_le32(DST_BRES_ERR, 0);
     aty_st_le32(DST_BRES_INC, 0);
@@ -766,23 +746,22 @@
     /* input */
     xres = var->xres;
     yres = var->yres;
-    vxres = var->xres_virtual;
-    vyres = var->yres_virtual;
+    vxres   = var->xres_virtual;
+    vyres   = var->yres_virtual;
     xoffset = var->xoffset;
     yoffset = var->yoffset;
-    bpp = var->bits_per_pixel;
-    left = var->left_margin;
+    bpp   = var->bits_per_pixel;
+    left  = var->left_margin;
     right = var->right_margin;
     upper = var->upper_margin;
     lower = var->lower_margin;
     hslen = var->hsync_len;
     vslen = var->vsync_len;
-    sync = var->sync;
+    sync  = var->sync;
     vmode = var->vmode;
 
-    /* check for mode eligibility */
-
-    /* accept only non interlaced modes */
+    /* check for mode eligibility
+     * accept only non interlaced modes */
     if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
 	return -EINVAL;
 
@@ -796,6 +775,7 @@
     if (vyres < yres + yoffset)
 	vyres = yres + yoffset;
 
+    /* convert bpp into ATI register depth */
     depth = bpp_to_depth(bpp);
 
     /* make sure we didn't get an invalid depth */
@@ -804,7 +784,8 @@
         return -EINVAL;
     }
 
-   bytpp = mode_bytpp[depth];
+    /* convert depth to bpp */
+    bytpp = mode_bytpp[depth];
 
     /* make sure there is enough video ram for the mode */
     if ((u32)(vxres * vyres * bytpp) > info->vram_size) {
@@ -813,24 +794,24 @@
     }
 
     h_disp = (xres >> 3) - 1;
-    h_total = (((xres + right + hslen + left) / 8) - 1) & 0xFFFFL;
+    h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL;
 
     v_disp = yres - 1;
     v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL;
 
     /* check to make sure h_total and v_total are in range */
-    if ((h_total/8 - 1) > 0x1ff || (v_total - 1) > 0x7FF) {
+    if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) {
         printk(KERN_ERR "aty128fb: invalid width ranges\n");
         return -EINVAL;
     }
 
-    h_sync_wid = (hslen+7)/8;
+    h_sync_wid = (hslen + 7) >> 3;
     if (h_sync_wid == 0)
 	h_sync_wid = 1;
     else if (h_sync_wid > 0x3f)        /* 0x3f = max hwidth */
 	h_sync_wid = 0x3f;
 
-    h_sync_strt = h_disp + (right/8);
+    h_sync_strt = h_disp + (right >> 3);
 
     v_sync_wid = vslen;
     if (v_sync_wid == 0)
@@ -855,7 +836,7 @@
     crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) |
                 (v_sync_pol << 23);
 
-    crtc->pitch = xres >> 3;
+    crtc->pitch = vxres >> 3;
 
     crtc->offset = 0;
     crtc->offset_cntl = 0;
@@ -922,7 +903,7 @@
 	var->transp.length = 8;
 	break;
     default:
-        printk(KERN_ERR "Invalid pixel width\n");
+        printk(KERN_ERR "aty128fb: Invalid pixel width\n");
         return -EINVAL;
     }
 
@@ -941,26 +922,27 @@
 
     /* fun with masking */
     h_total     = crtc->h_total & 0x1ff;
-    h_disp      = (crtc->h_total>>16) & 0xff;
-    h_sync_strt = (crtc->h_sync_strt_wid>>3) & 0x1ff;
+    h_disp      = (crtc->h_total >> 16) & 0xff;
+    h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff;
     h_sync_dly  = crtc->h_sync_strt_wid & 0x7;
-    h_sync_wid  = (crtc->h_sync_strt_wid>>16) & 0x3f;
-    h_sync_pol  = (crtc->h_sync_strt_wid>>23) & 0x1;
+    h_sync_wid  = (crtc->h_sync_strt_wid >> 16) & 0x3f;
+    h_sync_pol  = (crtc->h_sync_strt_wid >> 23) & 0x1;
     v_total     = crtc->v_total & 0x7ff;
-    v_disp      = (crtc->v_total>>16) & 0x7ff;
+    v_disp      = (crtc->v_total >> 16) & 0x7ff;
     v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
-    v_sync_wid  = (crtc->v_sync_strt_wid>>16) & 0x1f;
-    v_sync_pol  = (crtc->v_sync_strt_wid>>23) & 0x1;
+    v_sync_wid  = (crtc->v_sync_strt_wid >> 16) & 0x1f;
+    v_sync_pol  = (crtc->v_sync_strt_wid >> 23) & 0x1;
     c_sync      = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
     pix_width   = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
 
-    xres  = (h_disp+1) << 3;
-    yres  = v_disp+1;
-    left  = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
-    right = (h_sync_strt-h_disp)*8+h_sync_dly;
-    hslen = h_sync_wid*8;
-    upper = v_total-v_sync_strt-v_sync_wid;
-    lower = v_sync_strt-v_disp;
+    /* do conversions */
+    xres  = (h_disp + 1) << 3;
+    yres  = v_disp + 1;
+    left  = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly;
+    right = ((h_sync_strt - h_disp) << 3) + h_sync_dly;
+    hslen = h_sync_wid << 3;
+    upper = v_total - v_sync_strt - v_sync_wid;
+    lower = v_sync_strt - v_disp;
     vslen = v_sync_wid;
     sync  = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
             (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
@@ -974,13 +956,13 @@
     var->yres_virtual = crtc->vyres;
     var->xoffset = crtc->xoffset;
     var->yoffset = crtc->yoffset;
-    var->left_margin = left;
+    var->left_margin  = left;
     var->right_margin = right;
     var->upper_margin = upper;
     var->lower_margin = lower;
     var->hsync_len = hslen;
     var->vsync_len = vslen;
-    var->sync = sync;
+    var->sync  = sync;
     var->vmode = FB_VMODE_NONINTERLACED;
 
     return 0;
@@ -990,7 +972,7 @@
 static void
 aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info)
 {
-    int div3;
+    u32 div3;
 
     unsigned char post_conv[] =	/* register values for post dividers */
         { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
@@ -1003,25 +985,23 @@
 		aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);
 
     /* write the reference divider */
+    aty_pll_wait_readupdate(info);
     aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider & 0x3ff);
     aty_pll_writeupdate(info);
-    aty_pll_wait_readupdate(info);
 
     div3 = aty_ld_pll(PPLL_DIV_3);
-
     div3 &= ~PPLL_FB3_DIV_MASK;
     div3 |= pll->feedback_divider;
-
     div3 &= ~PPLL_POST3_DIV_MASK;
     div3 |= post_conv[pll->post_divider] << 16;
 
     /* write feedback and post dividers */
+    aty_pll_wait_readupdate(info);
     aty_st_pll(PPLL_DIV_3, div3);
     aty_pll_writeupdate(info);
-    aty_pll_wait_readupdate(info);
 
+    aty_pll_wait_readupdate(info);
     aty_st_pll(HTOTAL_CNTL, 0);	/* no horiz crtc adjustment */
-
     aty_pll_writeupdate(info);
 
     /* clear the reset, just in case */
@@ -1111,7 +1091,7 @@
 	bpp = 16;
 
     n = xclk * fifo_width;
-    d = pll->vclk*bpp;
+    d = pll->vclk * bpp;
     x = round_div(n, d);
 
     ron = 4 * m->MB +
@@ -1162,13 +1142,6 @@
 			struct fb_info_aty128 *info)
 { 
     u32 config;
-#ifdef CONFIG_FB_COMPAT_XPMAC
-#if 0 /* enable this when macmodes gets updated */
-    struct vc_mode disp_info;
-#endif
-    struct fb_var_screeninfo var;
-    int cmode, vmode;
-#endif
 
     info->current_par = *par;
     
@@ -1210,31 +1183,15 @@
     if (par->accel_flags & FB_ACCELF_TEXT)
         aty128_init_engine(par, info);
 
-#if 0/*def CONFIG_FB_COMPAT_XPMAC*/
-#if 0 /* use this when macmodes gets updated */
-    if (!console_fb_info || console_fb_info == &info->fb_info) {
-	disp_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1;
-	disp_info.height = (((par->crtc.h_total >> 16) & 0xff)+1) << 3;
-	disp_info.depth = par->crtc.bpp;
-	disp_info.pitch = par->crtc.vxres*par->crtc.bpp >> 3;
-        aty128_encode_var(&var, par, info);
-	if (mac_var_to_vmode(&var, &vmode, &cmode))
-	    disp_info.mode = 0;
-	else
-	    disp_info.mode = vmode;
-	strcpy(disp_info.name, aty128fb_name);
-	disp_info.fb_address = info->frame_buffer_phys;
-	disp_info.cmap_adr_address = 0;
-	disp_info.cmap_data_address = 0;
-	disp_info.disp_reg_address = info->regbase_phys;
-        register_compat_xpmac(disp_info);
-    }
-#else
+#ifdef CONFIG_FB_COMPAT_XPMAC
     if (!console_fb_info || console_fb_info == &info->fb_info) {
-	display_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1;
-	display_info.height = (((par->crtc.h_total >> 16) & 0xff)+1) << 3;
+        struct fb_var_screeninfo var;
+        int cmode, vmode;
+
+	display_info.height = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
+	display_info.width = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
 	display_info.depth = par->crtc.bpp;
-	display_info.pitch = par->crtc.vxres*par->crtc.bpp >> 3;
+	display_info.pitch = (par->crtc.vxres * par->crtc.bpp) >> 3;
         aty128_encode_var(&var, par, info);
 	if (mac_var_to_vmode(&var, &vmode, &cmode))
 	    display_info.mode = 0;
@@ -1245,9 +1202,7 @@
 	display_info.cmap_adr_address = 0;
 	display_info.cmap_data_address = 0;
 	display_info.disp_reg_address = info->regbase_phys;
-        register_compat_xpmac(display_info);
     }
-#endif
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
@@ -1491,15 +1446,15 @@
     
     strcpy(fix->id, aty128fb_name);
 
-    fix->smem_start = (long)info->frame_buffer_phys;
-    fix->mmio_start = (long)info->regbase_phys;
+    fix->smem_start = (unsigned long)info->frame_buffer_phys;
+    fix->mmio_start = (unsigned long)info->regbase_phys;
 
-    fix->smem_len = (u32)info->vram_size;
+    fix->smem_len = info->vram_size;
     fix->mmio_len = 0x1fff;
 
     fix->type        = FB_TYPE_PACKED_PIXELS;
     fix->type_aux    = 0;
-    fix->line_length = par->crtc.vxres*par->crtc.bpp >> 3;
+    fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3;
     fix->visual      = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
                                           : FB_VISUAL_DIRECTCOLOR;
     fix->ywrapstep = 0;
@@ -1547,7 +1502,7 @@
     u32 offset;
     u32 xres, yres;
 
-    xres = (((par->crtc.h_total >> 16) & 0xff) + 1) * 8;
+    xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
     yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
 
     xoffset = (var->xoffset +7) & ~7;
@@ -1617,7 +1572,6 @@
     return 0;                
 }
 
-
     /*
      *  Frame Buffer Specific ioctls
      */
@@ -1630,6 +1584,18 @@
 }
 
 
+static int
+aty128fb_rasterimg(struct fb_info *info, int start)
+{
+    struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info;
+
+    if (fb->blitter_may_be_busy)
+        wait_for_idle(fb);
+
+    return 0;
+}
+
+
 #ifndef MODULE
 int __init
 aty128fb_setup(char *options)
@@ -1742,12 +1708,13 @@
 
     /* fill in info */
     strcpy(info->fb_info.modename, aty128fb_name);
-    info->fb_info.node = -1;
+    info->fb_info.node  = -1;
     info->fb_info.fbops = &aty128fb_ops;
-    info->fb_info.disp = &info->disp;
+    info->fb_info.disp  = &info->disp;
     strcpy(info->fb_info.fontname, fontname);
-    info->fb_info.changevar = NULL;
+    info->fb_info.changevar  = NULL;
     info->fb_info.switch_con = &aty128fbcon_switch;
+    info->fb_info.updatevar  = NULL;
     info->fb_info.blank = &aty128fbcon_blank;
     info->fb_info.flags = FBINFO_FLAG_DEFAULT;
 
@@ -1755,7 +1722,7 @@
     var = default_var;
 #else
     memset(&var, 0, sizeof(var));
-#ifdef CONFIG_FB_COMPAT_XPMAC       /* CONFIG_PPC implied */
+#ifdef CONFIG_PPC
     if (_machine == _MACH_Pmac) {
         if (mode_option) {
             if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
@@ -1777,12 +1744,14 @@
             if (mac_vmode_to_var(default_vmode, default_cmode, &var))
                 var = default_var;
         }
+    } else {
+#endif /* CONFIG_PPC */
+        if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
+                          &defaultmode, initdepth) == 0)
+            var = default_var;
+#ifdef CONFIG_PPC
     }
-#else
-    if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
-                      &defaultmode, initdepth) == 0)
-        var = default_var;
-#endif /* CONFIG_FB_COMPAT_XPMAC */
+#endif
 #endif /* MODULE */
 
     if (noaccel)
@@ -1873,35 +1842,36 @@
                                const struct aty128_chip_info *aci)
 {
     struct fb_info_aty128 *info = NULL;
-    unsigned long fb_addr, reg_addr = 0;
-    u16 tmp;
-
-    struct resource *rp;
+    u32 fb_addr, reg_addr, io_addr = 0;
+    int err;
 
-    rp = &pdev->resource[0];
-    fb_addr = rp->start;
-    fb_addr &= PCI_BASE_ADDRESS_MEM_MASK;
+    /* Request resources we're going to use */
+    io_addr = pci_resource_start(pdev, 1);
+    if (!request_region(io_addr, pci_resource_len(pdev, 1),
+                        "aty128fb IO")) {
+        printk(KERN_ERR "aty128fb: cannot reserve I/O ports\n");
+        goto err_out_none;
+    }
 
-    if (!request_mem_region(rp->start, rp->end - rp->start + 1,
+    fb_addr = pci_resource_start(pdev, 0);
+    if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0),
                             "aty128fb FB")) {
-        release_mem_region(pdev->resource[0].start,
-                           pdev->resource[0].end -
-                           pdev->resource[0].start + 1);
-        return -1;
+        printk(KERN_ERR "aty128fb: cannot reserve frame buffer memory\n");
+        goto err_free_fb;
     }
 
-    rp = &pdev->resource[2];
-    reg_addr = rp->start;
-    reg_addr &= PCI_BASE_ADDRESS_MEM_MASK;
-
-    if (!request_mem_region(rp->start, rp->end - rp->start + 1,
-                            "aty128fb MMIO"))
-        goto unmap_out;
+    reg_addr = pci_resource_start(pdev, 2);
+    if (!request_mem_region(reg_addr, pci_resource_len(pdev, 2),
+                            "aty128fb MMIO")) {
+        printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n");
+        goto err_free_mmio;
+    }
 
+    /* We have the resources. Now virtualize them */
     info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
     if(!info) {
         printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
-	goto unmap_out;
+	goto err_unmap_out;
     }
     memset(info, 0, sizeof(struct fb_info_aty128));
 
@@ -1913,22 +1883,29 @@
     info->regbase = ioremap(reg_addr, 0x1FFF);
 
     if (!info->regbase)
-        goto err_out;
+        goto err_free_info;
 
-    info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+    /* Store io_base */
+    info->io_base = io_addr;
 
-    pci_read_config_word(pdev, PCI_COMMAND, &tmp);
-    if (!(tmp & PCI_COMMAND_MEMORY)) {
-        tmp |= PCI_COMMAND_MEMORY;
-        pci_write_config_word(pdev, PCI_COMMAND, tmp);
-    }
+    /* Grab memory size from the card */
+    info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
 
     /* Virtualize the framebuffer */
     info->frame_buffer_phys = fb_addr;
-    info->frame_buffer = (unsigned long)ioremap(fb_addr, info->vram_size);
+    info->frame_buffer = (u32)ioremap(fb_addr, info->vram_size);
+
+    if (!info->frame_buffer) {
+        iounmap((void *)info->regbase);
+        goto err_free_info;
+    }
 
-    if (!info->frame_buffer)
+    /* Enable device in PCI config */
+    err = pci_enable_device(pdev);
+    if (err) {
+        printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", err);
         goto err_out;
+    }
 
     /* If we can't test scratch registers, something is seriously wrong */
     if (!register_test(info)) {
@@ -1936,21 +1913,17 @@
         goto err_out;
     }
 
-    if (!aty128find_ROM(info)) {
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
+    if (!aty128find_ROM(info))
         printk(KERN_INFO "aty128fb: Rage128 BIOS not located. Guessing...\n");
-        aty128_timings(info);
-    }
-#ifndef CONFIG_PPC
- else
+    else
         aty128_get_pllinfo(info);
-
-        /* free up to-be unused resources. bios_seg is mapped by
-         * aty128find_ROM() and used by aty128_get_pllinfo()
-         *
-         * TODO: make more elegant. doesn't need to be global */
-        if (bios_seg)
-            iounmap(bios_seg);
 #endif
+    aty128_timings(info);
+
+    if (!aty128_init(info, "PCI"))
+        goto err_out;
+
 #ifdef CONFIG_MTRR
     if (mtrr) {
         info->mtrr.vram = mtrr_add(info->frame_buffer_phys, info->vram_size,
@@ -1961,32 +1934,34 @@
     }
 #endif /* CONFIG_MTRR */
 
-    if (!aty128_init(info, "PCI"))
-        goto err_out;
-
     return 0;
 
 err_out:
+    iounmap((void *)info->frame_buffer);
+    iounmap((void *)info->regbase);
+err_free_info:
     kfree(info);
-unmap_out:
-    release_mem_region(pdev->resource[0].start,
-			pdev->resource[0].end -
-			pdev->resource[0].start + 1);
-    release_mem_region(pdev->resource[2].start,
-			pdev->resource[2].end -
-			pdev->resource[2].start + 1);
-
-    return -1;
+err_unmap_out:
+    release_mem_region(pci_resource_start(pdev, 2),
+			pci_resource_len(pdev, 2));
+err_free_mmio:
+    release_mem_region(pci_resource_start(pdev, 0),
+			pci_resource_len(pdev, 0));
+err_free_fb:
+    release_mem_region(pci_resource_start(pdev, 1),
+			pci_resource_len(pdev, 1));
+err_out_none:
+    return -ENODEV;
 }
 #endif /* CONFIG_PCI */
 
 
-/* PPC cannot read video ROM, so we fail by default */
+/* PPC and Sparc cannot read video ROM */
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
 static int __init
 aty128find_ROM(struct fb_info_aty128 *info)
 {
     int  flag = 0;
-#ifndef CONFIG_PPC
     u32  segstart;
     char *rom_base;
     char *rom;
@@ -2043,12 +2018,10 @@
         flag = 1;
         break;
     }
-#endif /* !CONFIG_PPC */
     return (flag);
 }
 
 
-#ifndef CONFIG_PPC
 static void __init
 aty128_get_pllinfo(struct fb_info_aty128 *info)
 {   
@@ -2076,11 +2049,12 @@
     info->constants.ref_divider = (u32)pll.PCLK_ref_divider;
     info->constants.dotclock = (u32)pll.PCLK_ref_freq;
 
-    aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
-    aty_pll_writeupdate(info);
-
-    info->constants.fifo_width = 128;
-    info->constants.fifo_depth = 32;
+    /* free up to be un-used resources. bios_seg is mapped by
+     * aty128find_ROM() and used by aty128_get_pllinfo()
+     *
+     * TODO: make more elegant. doesn't need to be global */
+    if (bios_seg)
+        iounmap(bios_seg);
 
 #ifdef DEBUG
     printk(KERN_DEBUG "get_pllinfo: ppll_max %d ppll_min %d xclk %d "
@@ -2089,56 +2063,59 @@
                    info->constants.xclk, info->constants.ref_divider,
                    info->constants.dotclock);
 #endif
-
-    switch(aty_ld_le32(MEM_CNTL) & 0x03) {
-    case 0:
-        info->mem = &sdr_128; 
-        break;
-    case 1:
-        info->mem = &sdr_sgram;
-        break;  
-    case 2: 
-        info->mem = &ddr_sgram;
-        break;  
-    default:        
-        info->mem = &sdr_sgram;
-    }       
-
     return;
 }           
-#endif /* ! CONFIG_PPC */
+#endif /* !CONFIG_PPC */
 
 
 /* fill in known card constants if pll_block is not available */
 static void __init
 aty128_timings(struct fb_info_aty128 *info)
 {
-    /* TODO make an attempt at probing */
+#ifdef CONFIG_PPC
+    /* instead of a table lookup, assume OF has properly
+     * setup the PLL registers and use their values
+     * to set the XCLK values and reference divider values */
+
+    u32 x_mpll_ref_fb_div;
+    u32 xclk_cntl;
+    u32 Nx, M;
+    unsigned PostDivSet[] =
+        { 0, 1, 2, 4, 8, 3, 6, 12 };
+#endif
+
     if (!info->constants.dotclock)
         info->constants.dotclock = 2950;
 
-    /* from documentation */
-    if (!info->constants.ppll_min)
-        info->constants.ppll_min = 12500;
-    if (!info->constants.ppll_max)
-        info->constants.ppll_max = 25000;    /* 23000 on some cards? */
+#ifdef CONFIG_PPC
+    x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
+    xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
+    Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
+    M  = x_mpll_ref_fb_div & 0x0000ff;
+
+    info->constants.xclk = round_div((2 * Nx *
+        info->constants.dotclock), (M * PostDivSet[xclk_cntl]));
+
+    info->constants.ref_divider =
+        aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+#endif
 
-#if 1
-    /* XXX TODO. Calculuate properly. */
-    if (!info->constants.ref_divider)
+    if (!info->constants.ref_divider) {
         info->constants.ref_divider = 0x3b;
-    aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
-    aty_pll_writeupdate(info);
 
-    aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+        aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+        aty_pll_writeupdate(info);
+    }
+    aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
     aty_pll_writeupdate(info);
-#else
-    info->constants.ref_divider = aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
-#endif
 
-    /* TODO. Calculate */
+    /* from documentation */
+    if (!info->constants.ppll_min)
+        info->constants.ppll_min = 12500;
+    if (!info->constants.ppll_max)
+        info->constants.ppll_max = 25000;    /* 23000 on some cards? */
     if (!info->constants.xclk)
-        info->constants.xclk = 0x1d4d;	  /* same as mclk */
+        info->constants.xclk = 0x1d4d;	     /* same as mclk */
 
     info->constants.fifo_width = 128;
     info->constants.fifo_depth = 32;
@@ -2225,7 +2202,6 @@
     return 0;
 }
 
-
     /*
      *  Set a single color register. The values supplied are already
      *  rounded down to the hardware's capabilities (according to the
@@ -2314,22 +2290,36 @@
      *  Accelerated functions
      */
 
-static void
+static inline void
 aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
 		u_int width, u_int height,
 		struct fb_info_aty128 *info)
 {
-    u32 save_dp_datatype, save_dp_cntl;
+    u32 save_dp_datatype, save_dp_cntl, bppval;
+
+    if (!width || !height)
+        return;
+
+    bppval = bpp_to_depth(info->current_par.crtc.bpp);
+    if (bppval == DST_24BPP) {
+        srcx *= 3;
+        dstx *= 3;
+        width *= 3;
+    } else if (bppval == -EINVAL) {
+        printk("aty128fb: invalid depth\n");
+        return;
+    }
 
     wait_for_fifo(2, info);
     save_dp_datatype = aty_ld_le32(DP_DATATYPE);
     save_dp_cntl     = aty_ld_le32(DP_CNTL);
 
     wait_for_fifo(6, info);
-    aty_st_le32(DP_DATATYPE, (BRUSH_SOLIDCOLOR << 16) | SRC_DSTCOLOR);
+    aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
     aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
     aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
-    aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
+    aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR);
+
     aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
     aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
 
@@ -2338,8 +2328,6 @@
     wait_for_fifo(2, info);
     aty_st_le32(DP_DATATYPE, save_dp_datatype);
     aty_st_le32(DP_CNTL, save_dp_cntl); 
-
-    wait_for_idle(info);
 }
 
 
@@ -2569,12 +2557,12 @@
         iounmap(info->regbase);
         iounmap(&info->frame_buffer);
 
-        release_mem_region(info->pdev->resource[0].start,
-                           info->pdev->resource[0].end -
-                           info->pdev->resource[0].start + 1);
-        release_mem_region(info->pdev->resource[2].start,
-                           info->pdev->resource[2].end -
-                           info->pdev->resource[2].start + 1);
+        release_mem_region(pci_resource_start(info->pdev, 0),
+                           pci_resource_len(info->pdev, 0));
+        release_mem_region(pci_resource_start(info->pdev, 1),
+                           pci_resource_len(info->pdev, 1));
+        release_mem_region(pci_resource_start(info->pdev, 2),
+                           pci_resource_len(info->pdev, 2));
 
         kfree(info);
     }
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- v2.3.99-pre5/linux/drivers/video/cyber2000fb.c	Sun Mar 19 18:35:31 2000
+++ linux/drivers/video/cyber2000fb.c	Tue Apr 25 17:38:33 2000
@@ -616,8 +616,8 @@
  *   mult = reg0xb0.7:0
  *   div1 = (reg0xb1.5:0 + 1)
  *   div2 =  2^(reg0xb1.7:6)
- *   fpll should be between 115 and 257 MHz
- *  (8696ps and 3891ps)
+ *   fpll should be between 115 and 260 MHz
+ *  (8696ps and 3846ps)
  */
 static int
 cyber2000fb_decode_clock(struct par_info *hw, struct fb_var_screeninfo *var)
@@ -631,7 +631,7 @@
 
 	/*
 	 * Step 1:
-	 *   find div2 such that 115MHz < fpll < 257MHz
+	 *   find div2 such that 115MHz < fpll < 260MHz
 	 *   and 0 <= div2 < 4
 	 */
 	if (current_par.dev_id == PCI_DEVICE_ID_INTERG_2010)
@@ -643,7 +643,7 @@
 		unsigned long new_pll;
 
 		new_pll = pll_ps / divisors[div2];
-		if (8696 > new_pll && new_pll > 3891) {
+		if (8696 > new_pll && new_pll > 3846) {
 			pll_ps = new_pll;
 			break;
 		}
@@ -655,8 +655,10 @@
 #if 0
 	/*
 	 * Step 2:
-	 *  Find fpll
-	 *    fpll = fref * mult / div1
+	 *  Given pll_ps and ref_ps, find:
+	 *    pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
+	 *  where { 0 < div1 < 32, 0 < mult < 256 }
+	 *    pll_ps_calc = div1 / (ref_ps * mult)
 	 *
 	 * Note!  This just picks any old values at the moment,
 	 * and as such I don't trust it.  It certainly doesn't
@@ -1172,13 +1174,42 @@
 	cyber2000fb_ioctl
 };
 
+/*
+ * Enable access to the extended registers
+ *  Bug: this should track the usage of these registers
+ */
+static void cyber2000fb_enable_extregs(void)
+{
+	int old;
+
+	old = cyber2000_grphr(FUNC_CTL);
+	cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL);
+}
+
+/*
+ * Disable access to the extended registers
+ *  Bug: this should track the usage of these registers
+ */
+static void cyber2000fb_disable_extregs(void)
+{
+	int old;
+
+	old = cyber2000_grphr(FUNC_CTL);
+	cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL);
+}
+
+/*
+ * Attach a capture/tv driver to the core CyberX0X0 driver.
+ */
 int cyber2000fb_attach(struct cyberpro_info *info)
 {
 	if (current_par.initialised) {
-		info->dev     = current_par.dev;
-		info->regs    = CyberRegs;
-		info->fb      = current_par.screen_base;
-		info->fb_size = current_par.screen_size;
+		info->dev	      = current_par.dev;
+		info->regs	      = CyberRegs;
+		info->fb	      = current_par.screen_base;
+		info->fb_size	      = current_par.screen_size;
+		info->enable_extregs  = cyber2000fb_enable_extregs;
+		info->disable_extregs = cyber2000fb_disable_extregs;
 
 		strncpy(info->dev_name, current_par.dev_name, sizeof(info->dev_name));
 
@@ -1188,6 +1219,9 @@
 	return current_par.initialised;
 }
 
+/*
+ * Detach a capture/tv driver from the core CyberX0X0 driver.
+ */
 void cyber2000fb_detach(void)
 {
 	MOD_DEC_USE_COUNT;
@@ -1496,7 +1530,7 @@
 	v_sync = h_sync / (init_var.yres + init_var.upper_margin +
 		 init_var.lower_margin + init_var.vsync_len);
 
-	printk("%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	printk(KERN_INFO "%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
 		current_par.dev_name,
 		current_par.screen_size >> 10,
 		init_var.xres, init_var.yres,
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/cyber2000fb.h linux/drivers/video/cyber2000fb.h
--- v2.3.99-pre5/linux/drivers/video/cyber2000fb.h	Sun Mar 19 18:35:31 2000
+++ linux/drivers/video/cyber2000fb.h	Tue Apr 25 17:38:33 2000
@@ -26,6 +26,12 @@
 	cyber2000_outb(val, 0x3cf);
 }
 
+static inline unsigned int cyber2000_grphr(int reg)
+{
+	cyber2000_outb(reg, 0x3ce);
+	return cyber2000_inb(0x3cf);
+}
+
 static inline void cyber2000_attrw(int reg, int val)
 {
 	cyber2000_inb(0x3da);
@@ -145,6 +151,9 @@
 
 #define CAP_NEW_CTL2		0x89
 
+#define BM_CTRL0		0x9c
+#define BM_CTRL1		0x9d
+
 #define CAP_MODE1		0xa4
 #define CAP_MODE1_8BIT			0x01	/* enable 8bit capture mode		*/
 #define CAP_MODE1_CCIR656		0x02	/* CCIR656 mode				*/
@@ -244,11 +253,14 @@
 /*
  * Bus-master
  */
+#define BM_VID_ADDR_LOW		0xbc040
+#define BM_VID_ADDR_HIGH	0xbc044
 #define BM_ADDRESS_LOW		0xbc080
 #define BM_ADDRESS_HIGH		0xbc084
 #define BM_LENGTH		0xbc088
 #define BM_CONTROL		0xbc08c
 #define BM_CONTROL_ENABLE		0x01	/* enable transfer			*/
+#define BM_CONTROL_IRQEN		0x02	/* enable IRQ at end of transfer	*/
 #define BM_CONTROL_INIT			0x04	/* initialise status & count		*/
 #define BM_COUNT		0xbc090		/* read-only				*/
 
@@ -282,6 +294,12 @@
 	char		*fb;
 	char		dev_name[32];
 	unsigned int	fb_size;
+
+	/*
+	 * Use these to enable the BM or TV registers.
+	 */
+	void (*enable_extregs)(void);
+	void (*disable_extregs)(void);
 };
 
 /*
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c
--- v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p2.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/fbcon-iplan2p2.c	Fri Apr 14 09:37:10 2000
@@ -17,7 +17,10 @@
 #include <linux/fb.h>
 
 #include <asm/byteorder.h>
+
+#ifdef __mc68000__
 #include <asm/setup.h>
+#endif
 
 #include <video/fbcon.h>
 #include <video/fbcon-iplan2p2.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c
--- v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p4.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/fbcon-iplan2p4.c	Fri Apr 14 09:37:10 2000
@@ -17,7 +17,10 @@
 #include <linux/fb.h>
 
 #include <asm/byteorder.h>
+
+#ifdef __mc68000__
 #include <asm/setup.h>
+#endif
 
 #include <video/fbcon.h>
 #include <video/fbcon-iplan2p4.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c
--- v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p8.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/fbcon-iplan2p8.c	Fri Apr 14 09:37:10 2000
@@ -17,7 +17,10 @@
 #include <linux/fb.h>
 
 #include <asm/byteorder.h>
+
+#ifdef __mc68000__
 #include <asm/setup.h>
+#endif
 
 #include <video/fbcon.h>
 #include <video/fbcon-iplan2p8.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.99-pre5/linux/drivers/video/fbmem.c	Tue Apr 11 15:09:21 2000
+++ linux/drivers/video/fbmem.c	Tue Apr 25 17:58:46 2000
@@ -160,15 +160,15 @@
 #ifdef CONFIG_FB_ATY
 	{ "atyfb", atyfb_init, atyfb_setup },
 #endif
+#ifdef CONFIG_FB_ATY128
+	{ "aty128fb", aty128fb_init, aty128fb_setup },
+#endif
 #ifdef CONFIG_FB_OF
 	/*
 	 * Offb must be initialized _after_ all other frame buffer devices
 	 * that use PCI probing and PCI resources! [ Geert ]
 	 */
 	{ "offb", offb_init, offb_setup },
-#endif
-#ifdef CONFIG_FB_ATY128
-	{ "aty128fb", aty128fb_init, aty128fb_setup },
 #endif
 #ifdef CONFIG_FB_IGA
         { "igafb", igafb_init, igafb_setup },
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/mdacon.c linux/drivers/video/mdacon.c
--- v2.3.99-pre5/linux/drivers/video/mdacon.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/video/mdacon.c	Wed Apr 12 09:47:28 2000
@@ -5,6 +5,8 @@
  *
  *      including portions (c) 1995-1998 Patrick Caulfield.
  *
+ *      slight improvements (c) 2000 Edward Betts <edward@debian.org>
+ *
  *  This file is based on the VGA console driver (vgacon.c):
  *	
  *	Created 28 Sep 1997 by Geert Uytterhoeven
@@ -240,13 +242,18 @@
 	/* Ok, there is definitely a card registering at the correct
 	 * memory location, so now we do an I/O port test.
 	 */
-	
-	if (! test_mda_b(0x66, 0x0f)) {	    /* cursor low register */
+
+	/* Edward: These two mess `tests' mess up my cursor on bootup */
+
+	/* cursor low register */
+	/* if (! test_mda_b(0x66, 0x0f)) {
 		return 0;
-	}
-	if (! test_mda_b(0x99, 0x0f)) {     /* cursor low register */
+	} */
+
+	/* cursor low register */
+	/* if (! test_mda_b(0x99, 0x0f)) {
 		return 0;
-	}
+	} */
 
 	/* See if the card is a Hercules, by checking whether the vsync
 	 * bit of the status register is changing.  This test lasts for
@@ -339,6 +346,9 @@
 		mda_initialize();
 	}
 
+	/* cursor looks ugly during boot-up, so turn it off */
+	mda_set_cursor(mda_vram_len - 1);
+
 	printk("mdacon: %s with %ldK of memory detected.\n",
 		mda_type_name, mda_vram_len/1024);
 
@@ -494,13 +504,21 @@
 
 static int mdacon_blank(struct vc_data *c, int blank)
 {
-	if (blank) {
-		outb_p(0x00, mda_mode_port);	/* disable video */
+	if (mda_type == TYPE_MDA) {
+		if (blank) 
+			scr_memsetw((void *)mda_vram_base, 
+				mda_convert_attr(c->vc_video_erase_char),
+				c->vc_screenbuf_size);
+		/* Tell console.c that it has to restore the screen itself */
+		return 1;
 	} else {
-		outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
+		if (blank)
+			outb_p(0x00, mda_mode_port);	/* disable video */
+		else
+			outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, 
+				mda_mode_port);
+		return 0;
 	}
-	
-	return 0;
 }
 
 static int mdacon_font_op(struct vc_data *c, struct console_font_op *op)
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c
--- v2.3.99-pre5/linux/drivers/video/riva/fbdev.c	Mon Mar 27 08:08:28 2000
+++ linux/drivers/video/riva/fbdev.c	Wed Apr 12 09:16:31 2000
@@ -20,7 +20,7 @@
  */
 
 /* version number of this driver */
-#define RIVAFB_VERSION "0.7.0"
+#define RIVAFB_VERSION "0.7.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -99,6 +99,7 @@
 	CH_RIVA_TNT2,
 	CH_RIVA_UTNT2,	/* UTNT2 */
 	CH_RIVA_VTNT2,	/* VTNT2 */
+	CH_RIVA_UVTNT2,	/* VTNT2 */
 	CH_RIVA_ITNT2,	/* ITNT2 */
 };
 
@@ -113,6 +114,7 @@
 	{ "RIVA-TNT2", 5 },
 	{ "RIVA-UTNT2", 5 },
 	{ "RIVA-VTNT2", 5 },
+	{ "RIVA-UVTNT2", 5 },
 	{ "RIVA-ITNT2", 5 },
 };
 
@@ -123,6 +125,7 @@
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT2 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_UTNT2 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_ITNT2 },
 	{ 0, }, /* terminate list */
 };
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.3.99-pre5/linux/drivers/video/tdfxfb.c	Thu Jan  6 12:57:48 2000
+++ linux/drivers/video/tdfxfb.c	Fri Apr 14 09:37:10 2000
@@ -583,7 +583,9 @@
 static int  nopan   = 0;
 static int  nowrap  = 1;      // not implemented (yet)
 static int  inverse = 0;
+#ifdef CONFIG_MTRR
 static int  nomtrr = 0;
+#endif
 static int  nohwcursor = 0;
 static char __initdata fontname[40] = { 0 };
 static const char *mode_option __initdata = NULL;
@@ -1987,7 +1989,7 @@
       fb_info.regbase_phys = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
       fb_info.regbase_size = 1 << 24;
       fb_info.regbase_virt = 
-	(u32)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
+	(unsigned long)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
       if(!fb_info.regbase_virt) {
 	printk("fb: Can't remap %s register area.\n", name);
 	return;
@@ -2000,7 +2002,7 @@
 	return;
       }
       fb_info.bufbase_virt    = 
-	(u32)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
+	(unsigned long)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
       if(!fb_info.regbase_virt) {
 	printk("fb: Can't remap %s framebuffer.\n", name);
 	iounmap((void*)fb_info.regbase_virt);
@@ -2012,7 +2014,7 @@
       fb_info.regbase_phys = pdev->resource[0].start;
       fb_info.regbase_size = 1 << 24;
       fb_info.regbase_virt = 
-	(u32)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
+	(unsigned long)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
       if(!fb_info.regbase_virt) {
 	printk("fb: Can't remap %s register area.\n", name);
 	return -ENXIO;
@@ -2025,7 +2027,7 @@
 	return -ENXIO;
       }
       fb_info.bufbase_virt    = 
-	(u32)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
+	(unsigned long)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
       if(!fb_info.regbase_virt) {
 	printk("fb: Can't remap %s framebuffer.\n", name);
 	iounmap((void*)fb_info.regbase_virt);
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.3.99-pre5/linux/drivers/video/tgafb.c	Tue Apr 11 15:09:21 2000
+++ linux/drivers/video/tgafb.c	Wed Apr 12 09:47:28 2000
@@ -1,9 +1,9 @@
 /*
  *  linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device
  *
- *	Copyright (C) 1999 Martin Lucina, Tom Zerucha
+ *	Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
  *  
- *  $Id: tgafb.c,v 1.12 1999/07/01 13:39:23 mato Exp $
+ *  $Id: tgafb.c,v 1.12.2.3 2000/04/04 06:44:56 mato Exp $
  *
  *  This driver is partly based on the original TGA framebuffer device, which 
  *  was partly based on the original TGA console driver, which are
@@ -42,6 +42,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/selection.h>
+#include <linux/console.h>
 #include <asm/io.h>
 
 #include <video/fbcon.h>
@@ -59,7 +60,7 @@
 static int current_par_valid = 0;
 static struct display disp;
 
-static char __initdata default_fontname[40] = { 0 };
+static char default_fontname[40] = { 0 };
 static struct fb_var_screeninfo default_var;
 static int default_var_valid = 0;
 
@@ -112,10 +113,6 @@
   0x00000001
 };
 
-const unsigned int bt463_cursor_source[4] = {
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000
-};
-
 
     /*
      *  Predefined video modes
@@ -322,10 +319,11 @@
 
     fix->type = FB_TYPE_PACKED_PIXELS;
     fix->type_aux = 0;
-    if (fb_info.tga_type == 0) /* 8-plane */
+    if (fb_info.tga_type == TGA_TYPE_8PLANE) {
 	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-    else /* 24-plane or 24plusZ */
+    } else {
 	fix->visual = FB_VISUAL_TRUECOLOR;
+    }
 
     fix->line_length = par->xres * (par->bits_per_pixel >> 3);
     fix->smem_start = fb_info.tga_fb_base;
@@ -345,7 +343,7 @@
     struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
     /* round up some */
-    if (fb_info.tga_type == 0) {
+    if (fb_info.tga_type == TGA_TYPE_8PLANE) {
 	if (var->bits_per_pixel > 8) {
 	    return -EINVAL;
 	}
@@ -384,7 +382,11 @@
 	par->htimings |= TGA_HORIZ_POLARITY;
     if (var->sync & FB_SYNC_VERT_HIGH_ACT)
 	par->vtimings |= TGA_VERT_POLARITY;
-    /* what about sync on green? */
+    if (var->sync & FB_SYNC_ON_GREEN) {
+	par->sync_on_green = 1;
+    } else {
+	par->sync_on_green = 0;
+    }
 
     /* store other useful values in par */
     par->xres = var->xres; 
@@ -415,18 +417,19 @@
     	var->sync |= FB_SYNC_HOR_HIGH_ACT;
     if (par->vtimings & TGA_VERT_POLARITY)
     	var->sync |= FB_SYNC_VERT_HIGH_ACT;
+    if (par->sync_on_green == 1)
+	var->sync |= FB_SYNC_ON_GREEN;
 
     var->xres_virtual = var->xres;
     var->yres_virtual = var->yres;
     var->xoffset = var->yoffset = 0;
 
     /* depth-related */
-    if (fb_info.tga_type == 0) {
+    if (fb_info.tga_type == TGA_TYPE_8PLANE) {
 	var->red.offset = 0;
 	var->green.offset = 0;
 	var->blue.offset = 0;
     } else {
-	/* XXX: is this correct? */
 	var->red.offset = 16;
 	var->green.offset = 8;
 	var->blue.offset = 0;
@@ -456,7 +459,7 @@
     if (current_par_valid)
 	*par = current_par;
     else {
-	if (fb_info.tga_type == 0)
+	if (fb_info.tga_type == TGA_TYPE_8PLANE)
 	    default_var.bits_per_pixel = 8;
 	else
 	    default_var.bits_per_pixel = 32;
@@ -468,7 +471,7 @@
 
 static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info)
 {
-    int i, j, temp;
+    int i, j;
     struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
 #if 0
@@ -483,8 +486,8 @@
     current_par = *par;
     current_par_valid = 1;
 
-    /* first, disable video timing */
-    TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
+    /* first, disable video */
+    TGA_WRITE_REG(TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG);
     
     /* write the DEEP register */
     while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
@@ -515,10 +518,10 @@
     TGA_WRITE_REG(par->vtimings, TGA_VERT_REG);
 
     /* initalise RAMDAC */
-    if (fb_info.tga_type == 0) { /* 8-plane */
+    if (fb_info.tga_type == TGA_TYPE_8PLANE) { 
 
 	/* init BT485 RAMDAC registers */
-	BT485_WRITE(0xa2, BT485_CMD_0);
+	BT485_WRITE(0xa2 | (par->sync_on_green ? 0x8 : 0x0), BT485_CMD_0);
 	BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE);
 	BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */
 	BT485_WRITE(0x40, BT485_CMD_1);
@@ -545,69 +548,13 @@
 	    TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
 	}	  
 
-#if 0
-	/* initialize RAMDAC cursor colors */
-	BT485_WRITE(0, BT485_ADDR_CUR_WRITE);
-
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* overscan WHITE */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* overscan WHITE */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* overscan WHITE */
-
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
-
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */
-
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */
-	BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */
-
-	/* initialize RAMDAC cursor RAM */
-	BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE);
-
-	for (i = 0; i < tga_font_height_padded; i++)
-	    for (j = 7; j >= 0; j--) {
-#if 0
-		/* note that this is for a top-right alignment
-		 * - top left is commented out */
-		if( j > /*<*/ ((tga_font_width - 1) >> 3) ) {
-		    BT485_WRITE(0, BT485_CUR_RAM);
-		}
-		else if( j == ((tga_font_width - 1) >> 3) ) {
-		    BT485_WRITE((0xff >> /*<<*/
-				(7 - ((tga_font_width - 1)&7))) , BT485_CUR_RAM);
-		}
-		else {
-		    BT485_WRITE(0xff, BT485_CUR_RAM);
-		}
-#else
-		BT485_WRITE(0, BT485_CUR_RAM);
-#endif
-	    }
-	for (i = tga_font_height_padded; i < 64; i++)
-	    for (j = 0; j < 8; j++) {
-		BT485_WRITE(0, BT485_CUR_RAM);
-	    }
-	/* mask? */
-
-	for (i = 0; i < 512; i++) {
-	    BT485_WRITE(0xff, BT485_CUR_RAM);
-	}
-#endif
-
     } else { /* 24-plane or 24plusZ */
 
-	TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
-
-	/*
-	 * init some registers
-	 */
+	/* init BT463 registers */
 	BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
 	BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
-	BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2, 0x40);
+	BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2, 
+		(par->sync_on_green ? 0x80 : 0x40));
 
 	BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
 	BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
@@ -619,9 +566,7 @@
 	BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00);
 	BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00);
 
-	/*
-	 * fill the palette
-	 */
+	/* fill the palette */
 	BT463_LOAD_ADDR(0x0000);
 	TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
 
@@ -638,9 +583,7 @@
 	    TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
 	}	  
 
-	/*
-	 * fill window type table after start of vertical retrace
-	 */
+	/* fill window type table after start of vertical retrace */
 	while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01))
 	    continue;
 	TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG);
@@ -657,46 +600,12 @@
 	    TGA_WRITE_REG(0x01|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
 	    TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
 	}
-
-#if 0
-	/*
-	 * init cursor colors
-	 */
-	BT463_LOAD_ADDR(BT463_CUR_CLR_0);
-
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */
-
-	TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */
-	TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */
-	TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */
-
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-	TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-
-	/*
-	 * finally, init the cursor shape
-	 */
-	temp = tga_fb_base - 1024; /* this assumes video starts at base
-				     and base is beyond memory start*/
-
-	for (i = 0; i < tga_font_height_padded*4; i++)
-	    writel(bt463_cursor_source[i&3], temp + i*4);
-	for (i = tga_font_height_padded*4; i < 256; i++)
-	    writel(0, temp + i*4);
-	TGA_WRITE_REG(temp & 0x000fffff, TGA_CURSOR_BASE_REG);
-#endif
+   
     }
 
     /* finally, enable video scan
 	(and pray for the monitor... :-) */
-    TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
+    TGA_WRITE_REG(TGA_VALID_VIDEO, TGA_VALID_REG);
 }
 
 
@@ -814,11 +723,11 @@
     palette[regno].blue = blue;
 
 #ifdef FBCON_HAS_CFB32
-    if (regno < 16 && fb_info.tga_type != 0)
+    if (regno < 16 && fb_info.tga_type != TGA_TYPE_8PLANE)
 	fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
 #endif
 
-    if (fb_info.tga_type == 0) { /* 8-plane */
+    if (fb_info.tga_type == TGA_TYPE_8PLANE) { 
         BT485_WRITE(regno, BT485_ADDR_PAL_WRITE);
         TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
         TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
@@ -848,7 +757,7 @@
     if (con == currcon) {		/* current console? */
 	err = fb_set_cmap(cmap, kspc, tgafb_setcolreg, info);
 #if 1
-	if (fb_info.tga_type != 0)
+	if (fb_info.tga_type != TGA_TYPE_8PLANE)
 		tgafb_update_palette();
 #endif
 	return err;
@@ -886,7 +795,7 @@
 static int tgafb_blank(int blank, struct fb_info_gen *info)
 {
     static int tga_vesa_blanked = 0;
-    u32 vhcr, vvcr;
+    u32 vhcr, vvcr, vvvr;
     unsigned long flags;
     
     save_flags(flags);
@@ -894,6 +803,7 @@
 
     vhcr = TGA_READ_REG(TGA_HORIZ_REG);
     vvcr = TGA_READ_REG(TGA_VERT_REG);
+    vvvr = TGA_READ_REG(TGA_VALID_REG) & ~(TGA_VALID_VIDEO | TGA_VALID_BLANK);
 
     switch (blank) {
     case 0: /* Unblanking */
@@ -902,29 +812,29 @@
 	   TGA_WRITE_REG(vvcr & 0xbfffffff, TGA_VERT_REG);
 	   tga_vesa_blanked = 0;
 	}
- 	TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
+ 	TGA_WRITE_REG(vvvr | TGA_VALID_VIDEO, TGA_VALID_REG);
 	break;
 
     case 1: /* Normal blanking */
-	TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
+	TGA_WRITE_REG(vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG);
 	break;
 
     case 2: /* VESA blank (vsync off) */
 	TGA_WRITE_REG(vvcr | 0x40000000, TGA_VERT_REG);
-	TGA_WRITE_REG(0x02, TGA_VALID_REG); /* BLANK */
+	TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
 	tga_vesa_blanked = 1;
 	break;
 
     case 3: /* VESA blank (hsync off) */
 	TGA_WRITE_REG(vhcr | 0x40000000, TGA_HORIZ_REG);
-	TGA_WRITE_REG(0x02, TGA_VALID_REG); /* BLANK */
+	TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
 	tga_vesa_blanked = 1;
 	break;
 
     case 4: /* Poweroff */
 	TGA_WRITE_REG(vhcr | 0x40000000, TGA_HORIZ_REG);
 	TGA_WRITE_REG(vvcr | 0x40000000, TGA_VERT_REG);
-	TGA_WRITE_REG(0x02, TGA_VALID_REG); /* BLANK */
+	TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
 	tga_vesa_blanked = 1;
 	break;
     }
@@ -937,17 +847,17 @@
 static void tgafb_set_disp(const void *fb_par, struct display *disp,
 	struct fb_info_gen *info)
 {
-    disp->screen_base = fb_info.tga_fb_base;
+    disp->screen_base = (char *)fb_info.tga_fb_base;
     switch (fb_info.tga_type) {
 #ifdef FBCON_HAS_CFB8
-	case 0: /* 8-plane */
+	case TGA_TYPE_8PLANE:
 	    disp->dispsw = &fbcon_cfb8;
             break;
 #endif
 #ifdef FBCON_HAS_CFB32
-        case 1: /* 24-plane */
-        case 3: /* 24plusZ */
-            disp->dispsw = &fbcon_cfb32;
+        case TGA_TYPE_24PLANE:
+        case TGA_TYPE_24PLUSZ:
+	    disp->dispsw = &fbcon_cfb32; 
             disp->dispsw_data = &fbcon_cfb32_cmap;
             break;
 #endif
@@ -1003,22 +913,27 @@
     char *this_opt;
     int i;
     
-    if (options && *options)
+    if (options && *options) {
     	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
-       	    if (!*this_opt) continue;
+       	    if (!*this_opt) { continue; }
         
-	    if (!strncmp(this_opt, "font:", 5))
+	    if (!strncmp(this_opt, "font:", 5)) {
 	     	strncpy(default_fontname, this_opt+5, sizeof default_fontname);
+	    }
+
 	    else if (!strncmp(this_opt, "mode:", 5)) {
     		for (i = 0; i < NUM_TOTAL_MODES; i++) {
     		    if (!strcmp(this_opt+5, tgafb_predefined[i].name))
     			default_var = tgafb_predefined[i].var;
 		    	default_var_valid = 1;
     		}
-    	    } else {
+    	    } 
+	    
+	    else {
       		printk(KERN_ERR "tgafb: unknown parameter %s\n", this_opt);
     	    }
       	}
+    }
     return 0;
 }
 
@@ -1034,33 +949,17 @@
     pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
     if (!pdev)
 	return -ENXIO;
-    fb_info.tga_mem_base = ioremap(pdev->resource[0].start, 0);
 
-#ifdef DEBUG
-    printk(KERN_DEBUG "tgafb_init: mem_base 0x%x\n", fb_info.tga_mem_base);
-#endif /* DEBUG */
+    /* divine board type */
 
+    fb_info.tga_mem_base = (unsigned long)ioremap(pdev->resource[0].start, 0);
     fb_info.tga_type = (readl(fb_info.tga_mem_base) >> 12) & 0x0f;
     fb_info.tga_regs_base = fb_info.tga_mem_base + TGA_REGS_OFFSET;
     fb_info.tga_fb_base = (fb_info.tga_mem_base
 			   + fb_offset_presets[fb_info.tga_type]);
+    pci_read_config_byte(pdev, PCI_REVISION_ID, &fb_info.tga_chip_rev);
 
-    /* XXX Why the fuck is it called modename if it identifies the board? */
-    strcpy (fb_info.gen.info.modename,"DEC 21030 TGA "); 
-    switch (fb_info.tga_type) 
-    { 
-	case 0: /* 8-plane */
-	    strcat (fb_info.gen.info.modename, "8-plane");
-	    break;
-
-	case 1:
-	    strcat (fb_info.gen.info.modename, "24-plane");
-	    break;
-
-	case 3:
-	    strcat (fb_info.gen.info.modename, "24plusZ");
-	    break;
-    }
+    /* setup framebuffer */
 
     fb_info.gen.info.node = -1;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
@@ -1075,9 +974,30 @@
     fb_info.gen.fbhw = &tgafb_hwswitch;
     fb_info.gen.fbhw->detect();
 
+    printk (KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n", fb_info.tga_chip_rev);
+    printk (KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n", 
+	    pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+	    
+    switch (fb_info.tga_type) 
+    { 
+	case TGA_TYPE_8PLANE:
+	    strcpy (fb_info.gen.info.modename,"Digital ZLXp-E1"); 
+	    break;
+
+	case TGA_TYPE_24PLANE:
+	    strcpy (fb_info.gen.info.modename,"Digital ZLXp-E2"); 
+	    break;
+
+	case TGA_TYPE_24PLUSZ:
+	    strcpy (fb_info.gen.info.modename,"Digital ZLXp-E3"); 
+	    break;
+    }
+
     /* This should give a reasonable default video mode */
-    if (!default_var_valid)
+
+    if (!default_var_valid) {
 	default_var = tgafb_predefined[0].var;
+    }
     fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
     disp.var.activate = FB_ACTIVATE_NOW;
     fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
@@ -1085,8 +1005,9 @@
     fbgen_install_cmap(0, &fb_info.gen);
     if (register_framebuffer(&fb_info.gen.info) < 0)
 	return -EINVAL;
-    printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
-	fb_info.gen.info.modename);
+    printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n", 
+	    GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename, 
+	    pdev->resource[0].start);
     return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/tgafb.h linux/drivers/video/tgafb.h
--- v2.3.99-pre5/linux/drivers/video/tgafb.h	Wed Dec 15 10:43:17 1999
+++ linux/drivers/video/tgafb.h	Wed Apr 12 09:47:28 2000
@@ -1,9 +1,9 @@
 /*
  *  linux/drivers/video/tgafb.h -- DEC 21030 TGA frame buffer device
  *
- *  	Copyright (C) 1999 Martin Lucina, Tom Zerucha
+ *  	Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
  *  
- *  $Id: tgafb.h,v 1.4 1999/05/15 08:44:31 mato Exp $
+ *  $Id: tgafb.h,v 1.4.2.3 2000/04/04 06:44:56 mato Exp $
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
@@ -17,6 +17,9 @@
      * TGA hardware description (minimal)
      */
 
+#define TGA_TYPE_8PLANE			0
+#define TGA_TYPE_24PLANE		1
+#define TGA_TYPE_24PLUSZ		3
 
     /*
      * Offsets within Memory Space
@@ -50,7 +53,7 @@
 
 
     /* 
-     * useful defines for managing the video timing registers
+     * useful defines for managing the registers
      */
 
 #define TGA_HORIZ_ODD			0x80000000
@@ -69,6 +72,10 @@
 #define TGA_VERT_FP			0x0000f800
 #define TGA_VERT_ACTIVE			0x000007ff
 
+#define TGA_VALID_VIDEO			0x01
+#define TGA_VALID_BLANK			0x02
+#define TGA_VALID_CURSOR		0x04
+
 
     /*
      * useful defines for managing the ICS1562 PLL clock
@@ -167,10 +174,11 @@
     struct fb_info_gen gen;
 
     /* Device dependent information */
-    int tga_type;					/* TGA type: {8plane, 24plane, 24plusZ} */
-    unsigned long tga_mem_base;
-    unsigned long tga_fb_base;
-    unsigned long tga_regs_base;
+    u8 tga_type;					/* TGA_TYPE_XXX */
+    u8 tga_chip_rev;					/* dc21030 revision */
+    u64 tga_mem_base;
+    u64 tga_fb_base;
+    u64 tga_regs_base;
     struct fb_var_screeninfo default_var;		/* default video mode */
 };
 
@@ -180,11 +188,12 @@
      */
 
 struct tgafb_par {
-    int xres, yres;					/* resolution in pixels */
-    unsigned int htimings;				/* horizontal timing register */
-    unsigned int vtimings;				/* vertical timing register */
-    unsigned int pll_freq;				/* pixclock in mhz */
-    unsigned int bits_per_pixel;			/* bits per pixel */
+    u32 xres, yres;				/* resolution in pixels */
+    u32 htimings;				/* horizontal timing register */
+    u32 vtimings;				/* vertical timing register */
+    u32 pll_freq;				/* pixclock in mhz */
+    u32 bits_per_pixel;				/* bits per pixel */
+    u32 sync_on_green;				/* set if sync is on green */
 };
 
 #endif /* TGAFB_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/Config.in linux/fs/Config.in
--- v2.3.99-pre5/linux/fs/Config.in	Tue Apr 11 15:09:21 2000
+++ linux/fs/Config.in	Thu Apr 13 13:57:09 2000
@@ -12,7 +12,7 @@
 dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 dep_mbool '  ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 
-tristate 'Amiga FFS file system support' CONFIG_AFFS_FS
+dep_tristate 'Amiga FFS file system support (EXPERIMENTAL)' CONFIG_AFFS_FS $CONFIG_EXPERIMENTAL
 
 dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/adfs/inode.c linux/fs/adfs/inode.c
--- v2.3.99-pre5/linux/fs/adfs/inode.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/adfs/inode.c	Tue Apr 25 17:28:56 2000
@@ -49,7 +49,7 @@
 	return 0;
 }
 
-static int adfs_writepage(struct dentry *dentry, struct page *page)
+static int adfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page, adfs_get_block);
 }
@@ -73,6 +73,7 @@
 static struct address_space_operations adfs_aops = {
 	readpage:	adfs_readpage,
 	writepage:	adfs_writepage,
+	sync_page:	block_sync_page,
 	prepare_write:	adfs_prepare_write,
 	commit_write:	generic_commit_write,
 	bmap:		_adfs_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/affs/Changes linux/fs/affs/Changes
--- v2.3.99-pre5/linux/fs/affs/Changes	Sun Mar 21 07:11:37 1999
+++ linux/fs/affs/Changes	Thu Apr 13 13:57:09 2000
@@ -28,6 +28,12 @@
 
 Please direct bug reports to: hjw@zvw.de
 
+Version 3.11
+------------
+
+- Converted to use 2.3.x page cache [Dave Jones <dave@powertweak.com>]
+- Corruption in truncate() bugfix [Ken Tyler <kent@werple.net.au>]
+
 Version 3.10
 ------------
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- v2.3.99-pre5/linux/fs/affs/bitmap.c	Thu May  7 22:58:04 1998
+++ linux/fs/affs/bitmap.c	Wed Apr 12 09:47:28 2000
@@ -280,28 +280,17 @@
 affs_new_header(struct inode *inode)
 {
 	s32			 block;
-	struct buffer_head	*bh;
 
 	pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino);
 
 	if (!(block = affs_balloc(inode,0))) {
 		while (affs_find_new_zone(inode->i_sb,0)) {
 			if ((block = affs_balloc(inode,0)))
-				goto init_block;
+				return block;
 			schedule();
 		}
 		return 0;
 	}
-init_block:
-	if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
-		affs_error(inode->i_sb,"new_header","Cannot get block %d",block);
-		return 0;
-	}
-	memset(bh->b_data,0,AFFS_I2BSIZE(inode));
-	mark_buffer_uptodate(bh,1);
-	mark_buffer_dirty(bh,1);
-	affs_brelse(bh);
-
 	return block;
 }
 
@@ -314,7 +303,6 @@
 	unsigned long		 oldest;
 	struct affs_zone	*zone;
 	struct super_block	*sb;
-	struct buffer_head	*bh;
 	int			 i = 0;
 	s32			 block;
 
@@ -327,7 +315,7 @@
 		unlock_super(sb);
 		block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
 		inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
-		goto init_block;
+		return block;
 	}
 	unlock_super(sb);
 	oldest = jiffies;
@@ -364,24 +352,13 @@
 	if (!(block = affs_balloc(inode,i))) {		/* No data zones left */
 		while (affs_find_new_zone(sb,i)) {
 			if ((block = affs_balloc(inode,i)))
-				goto init_block;
+				return block;
 			schedule();
 		}
 		inode->u.affs_i.i_zone = 0;
 		zone->z_ino            = -1;
 		return 0;
 	}
-
-init_block:
-	if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
-		affs_error(inode->i_sb,"new_data","Cannot get block %d",block);
-		return 0;
-	}
-	memset(bh->b_data,0,sb->s_blocksize);
-	mark_buffer_uptodate(bh,1);
-	mark_buffer_dirty(bh,1);
-	affs_brelse(bh);
-
 	return block;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.3.99-pre5/linux/fs/affs/file.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/affs/file.c	Tue Apr 25 17:28:56 2000
@@ -13,6 +13,7 @@
  */
 
 #define DEBUG 0
+#include <asm/div64.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/sched.h>
@@ -23,6 +24,7 @@
 #include <linux/malloc.h>
 #include <linux/stat.h>
 #include <linux/locks.h>
+#include <linux/smp_lock.h>
 #include <linux/dirent.h>
 #include <linux/fs.h>
 #include <linux/amigaffs.h>
@@ -36,7 +38,6 @@
 #error PAGE_SIZE must be at least 4096
 #endif
 
-static int affs_bmap(struct inode *inode, int block);
 static struct buffer_head *affs_getblock(struct inode *inode, s32 block);
 static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos);
 static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
@@ -157,6 +158,8 @@
 
 	for (index = 0; index < 4; index++) {
 		kc = &inode->u.affs_i.i_ec->kc[index];
+		if (kc->kc_last == -1)
+			continue;	/* don't look in cache if invalid. */
 		if (*ext == kc->kc_this_seq) {
 			return kc->kc_this_key;
 		} else if (*ext == kc->kc_this_seq + 1) {
@@ -175,7 +178,7 @@
 	return inode->u.affs_i.i_ec->ec[index];
 }
 
-static int
+int
 affs_bmap(struct inode *inode, int block)
 {
 	struct buffer_head	*bh;
@@ -192,13 +195,14 @@
 
 	pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
 
+	lock_kernel();
 	if (block < 0) {
 		affs_error(inode->i_sb,"bmap","Block < 0");
-		return 0;
+		goto out_fail;
 	}
 	if (!inode->u.affs_i.i_ec) {
 		if (alloc_ext_cache(inode)) {
-			return 0;
+			goto out_fail;
 		}
 	}
 
@@ -212,6 +216,7 @@
 		tkc = &inode->u.affs_i.i_ec->kc[i];
 		/* Look in any cache if the key is there */
 		if (block <= tkc->kc_last && block >= tkc->kc_first) {
+			unlock_kernel();
 			return tkc->kc_keys[block - tkc->kc_first];
 		}
 	}
@@ -246,14 +251,15 @@
 
 	for (;;) {
 		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
-		if (!bh) 
-			return 0;
+		if (!bh)
+			goto out_fail;
+
 		index = seqnum_to_index(ext);
 		if (index > inode->u.affs_i.i_ec->max_ext &&
 		    (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
 		     (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE)) {
 			affs_brelse(bh);
-			return 0;
+			goto out_fail;
 		}
 		nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
 		if (block < AFFS_I2HSIZE(inode)) {
@@ -282,16 +288,57 @@
 	kc->kc_next_key = nkey;
 	key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
 	affs_brelse(bh);
+out:
+	unlock_kernel();
 	return key;
+
+out_fail:
+	key=0;
+	goto out;
 }
 
-/* AFFS is currently broken */
-static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
+
+static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
 {
-	BUG();
-	return -1;
+	int err, phys=0, new=0;
+
+	if (!create) {
+		phys = affs_bmap(inode, block);
+		if (phys) {
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
+		return 0;
+	}
+
+	err = -EIO;
+	lock_kernel();
+	if (block < 0)
+		goto abort_negative;
+
+	if (affs_getblock(inode, block)==NULL) {
+		err = -EIO;
+		goto abort;
+	}
+
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	if (new)
+		bh_result->b_state |= (1UL << BH_New);
+	
+abort:
+	unlock_kernel();
+	return err;
+
+abort_negative:
+	affs_error(inode->i_sb,"affs_get_block","Block < 0");
+	goto abort;
+
 }
-static int affs_writepage(struct dentry *dentry, struct page *page)
+		
+static int affs_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,affs_get_block);
 }
@@ -311,6 +358,7 @@
 struct address_space_operations affs_aops = {
 	readpage: affs_readpage,
 	writepage: affs_writepage,
+	sync_page: block_sync_page,
 	prepare_write: affs_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: _affs_bmap
@@ -325,8 +373,7 @@
  * What a mess.
  */
 
-static struct buffer_head *
-affs_getblock(struct inode *inode, s32 block)
+static struct buffer_head * affs_getblock(struct inode *inode, s32 block)
 {
 	struct super_block	*sb = inode->i_sb;
 	int			 ofs = sb->u.affs_sb.s_flags & SF_OFS;
@@ -340,9 +387,6 @@
 
 	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
 
-	if (block < 0)
-		goto out_fail;
-
 	key    = calc_key(inode,&ext);
 	block -= ext * AFFS_I2HSIZE(inode);
 	pt     = ext ? T_LIST : T_SHORT;
@@ -370,16 +414,14 @@
 		for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) {
 			if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
 				if (j > 0) {
-					s32 k = AFFS_BLOCK(bh->b_data, inode,
-								j - 1);
+					s32 k = AFFS_BLOCK(bh->b_data, inode, j - 1);
 					pbh = affs_bread(inode->i_dev,
 							be32_to_cpu(k),
 							AFFS_I2BSIZE(inode));
 				} else
 					pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
 				if (!pbh) {
-					affs_error(sb,"getblock",
-						"Cannot get last block in file");
+					affs_error(sb,"getblock", "Cannot get last block in file");
 					break;
 				}
 			}
@@ -396,8 +438,7 @@
 			if (ofs) {
 				ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
 				if (!ebh) {
-					affs_error(sb,"getblock",
-						   "Cannot get block %d",nkey);
+					affs_error(sb,"getblock", "Cannot get block %d",nkey);
 					affs_free_block(sb,nkey);
 					AFFS_BLOCK(bh->b_data,inode,j) = 0;
 					break;
@@ -405,8 +446,7 @@
 				DATA_FRONT(ebh)->primary_type    = cpu_to_be32(T_DATA);
 				DATA_FRONT(ebh)->header_key      = cpu_to_be32(inode->i_ino);
 				DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);
-				affs_fix_checksum(AFFS_I2BSIZE(inode),
-							ebh->b_data, 5);
+				affs_fix_checksum(AFFS_I2BSIZE(inode), ebh->b_data, 5);
 				mark_buffer_dirty(ebh, 0);
 				if (pbh) {
 					DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);
@@ -503,6 +543,7 @@
 	ssize_t			 blocksize;
 	struct buffer_head	*bh;
 	void			*data;
+	loff_t		tmp;
 
 	pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,
 		 (unsigned long)*ppos,count);
@@ -524,10 +565,13 @@
 		left = MIN (inode->i_size - *ppos,count - (buf - start));
 		if (!left)
 			break;
-		sector = affs_bmap(inode,(u32)*ppos / blocksize);
+		tmp = *ppos;
+		do_div(tmp, blocksize);
+		sector = affs_bmap(inode, tmp);
 		if (!sector)
 			break;
-		offset = (u32)*ppos % blocksize;
+		tmp = *ppos;
+		offset = do_div(tmp, blocksize);
 		bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
 		if (!bh)
 			break;
@@ -544,165 +588,31 @@
 }
 
 static ssize_t
-affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
+affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	struct inode		*inode = filp->f_dentry->d_inode;
-	off_t			 pos;
-	ssize_t			 written;
-	ssize_t			 c;
-	ssize_t			 blocksize;
-	struct buffer_head	*bh;
-	char			*p;
-
-	if (!count)
-		return 0;
-	pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
-		 (unsigned long)*ppos,count);
+	ssize_t retval;
 
-	if (!inode) {
-		affs_error(inode->i_sb,"file_write","Inode = NULL");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode)) {
-		affs_error(inode->i_sb,"file_write",
-			   "Trying to write to non-regular file (mode=%07o)",
-			   inode->i_mode);
-		return -EINVAL;
+	retval = generic_file_write (file, buf, count, ppos);
+	if (retval >0) {
+		struct inode *inode = file->f_dentry->d_inode;
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		mark_inode_dirty(inode);
 	}
-	if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode))
-		return -ENOMEM;
-	if (filp->f_flags & O_APPEND)
-		pos = inode->i_size;
-	else
-		pos = *ppos;
-	written   = 0;
-	blocksize = AFFS_I2BSIZE(inode);
-
-	while (written < count) {
-		bh = affs_getblock(inode,pos / blocksize);
-		if (!bh) {
-			if (!written)
-				written = -ENOSPC;
-			break;
-		}
-		c = blocksize - (pos % blocksize);
-		if (c > count - written)
-			c = count - written;
-		if (c != blocksize && !buffer_uptodate(bh)) {
-			ll_rw_block(READ,1,&bh);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh)) {
-				affs_brelse(bh);
-				if (!written)
-					written = -EIO;
-				break;
-			}
-		}
-		p  = (pos % blocksize) + bh->b_data;
-		c -= copy_from_user(p,buf,c);
-		if (!c) {
-			affs_brelse(bh);
-			if (!written)
-				written = -EFAULT;
-			break;
-		}
-		update_vm_cache(inode,pos,p,c);
-		mark_buffer_uptodate(bh,1);
-		mark_buffer_dirty(bh,0);
-		affs_brelse(bh);
-		pos     += c;
-		written += c;
-		buf     += c;
-	}
-	if (pos > inode->i_size)
-		inode->i_size = pos;
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	*ppos          = pos;
-	mark_inode_dirty(inode);
-	return written;
+	return retval;
 }
 
 static ssize_t
-affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos)
+affs_file_write_ofs(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	struct inode		*inode = filp->f_dentry->d_inode;
-	off_t			 pos;
-	ssize_t			 written;
-	ssize_t			 c;
-	ssize_t			 blocksize;
-	struct buffer_head	*bh;
-	char			*p;
-
-	pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
-		(unsigned long)*ppos,count);
+	ssize_t retval;
 
-	if (!count)
-		return 0;
-	if (!inode) {
-		affs_error(inode->i_sb,"file_write_ofs","Inode = NULL");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode)) {
-		affs_error(inode->i_sb,"file_write_ofs",
-			   "Trying to write to non-regular file (mode=%07o)",
-			   inode->i_mode);
-		return -EINVAL;
-	}
-	if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode))
-		return -ENOMEM;
-	if (filp->f_flags & O_APPEND)
-		pos = inode->i_size;
-	else
-		pos = *ppos;
-
-	bh        = NULL;
-	blocksize = AFFS_I2BSIZE(inode) - 24;
-	written   = 0;
-	while (written < count) {
-		bh = affs_getblock(inode,pos / blocksize);
-		if (!bh) {
-			if (!written)
-				written = -ENOSPC;
-			break;
-		}
-		c = blocksize - (pos % blocksize);
-		if (c > count - written)
-			c = count - written;
-		if (c != blocksize && !buffer_uptodate(bh)) {
-			ll_rw_block(READ,1,&bh);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh)) {
-				affs_brelse(bh);
-				if (!written)
-					written = -EIO;
-				break;
-			}
-		}
-		p  = (pos % blocksize) + bh->b_data + 24;
-		c -= copy_from_user(p,buf,c);
-		if (!c) {
-			affs_brelse(bh);
-			if (!written)
-				written = -EFAULT;
-			break;
-		}
-		update_vm_cache(inode,pos,p,c);
-
-		pos     += c;
-		buf     += c;
-		written += c;
-		DATA_FRONT(bh)->data_size = cpu_to_be32(be32_to_cpu(DATA_FRONT(bh)->data_size) + c);
-		affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-		mark_buffer_uptodate(bh,1);
-		mark_buffer_dirty(bh,0);
-		affs_brelse(bh);
+	retval = generic_file_write (file, buf, count, ppos);
+	if (retval >0) {
+		struct inode *inode = file->f_dentry->d_inode;
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		mark_inode_dirty(inode);
 	}
-	if (pos > inode->i_size)
-		inode->i_size = pos;
-	*ppos = pos;
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(inode);
-	return written;
+	return retval;
 }
 
 /* Free any preallocated blocks. */
@@ -746,11 +656,13 @@
 	int	 blocksize = AFFS_I2BSIZE(inode);
 	int	 rem;
 	int	 ext;
+	loff_t tmp;
 
 	pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
 
 	net_blocksize = blocksize - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
-	first = (inode->i_size + net_blocksize - 1) / net_blocksize;
+	first = inode->i_size + net_blocksize -1;
+	do_div (first, net_blocksize);
 	if (inode->u.affs_i.i_lastblock < first - 1) {
 		/* There has to be at least one new block to be allocated */
 		if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) {
@@ -762,7 +674,8 @@
 			affs_warning(inode->i_sb,"truncate","Cannot extend file");
 			inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1);
 		} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
-			rem = inode->i_size % net_blocksize;
+			tmp = inode->i_size;
+			rem = do_div(tmp, net_blocksize);
 			DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize);
 			affs_fix_checksum(blocksize,bh->b_data,5);
 			mark_buffer_dirty(bh,0);
@@ -829,7 +742,9 @@
 			affs_free_block(inode->i_sb,ekey);
 		ekey = key;
 	}
-	block = ((inode->i_size + net_blocksize - 1) / net_blocksize) - 1;
+	block = inode->i_size + net_blocksize - 1;
+	do_div (block, net_blocksize);
+	block--;
 	inode->u.affs_i.i_lastblock = block;
 
 	/* If the file is not truncated to a block boundary,
@@ -837,7 +752,8 @@
 	 * so it cannot become accessible again.
 	 */
 
-	rem = inode->i_size % net_blocksize;
+	tmp = inode->i_size;
+	rem = do_div(tmp, net_blocksize);
 	if (rem) {
 		if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) 
 			rem += 24;
@@ -860,7 +776,7 @@
 	/* Invalidate cache */
 	if (inode->u.affs_i.i_ec) {
 		inode->u.affs_i.i_ec->max_ext = 0;
-		for (key = 0; key < 3; key++) {
+		for (key = 0; key < 4; key++) {
 			inode->u.affs_i.i_ec->kc[key].kc_next_key = 0;
 			inode->u.affs_i.i_ec->kc[key].kc_last     = -1;
 		}
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.3.99-pre5/linux/fs/affs/inode.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/affs/inode.c	Wed Apr 12 09:47:28 2000
@@ -11,6 +11,7 @@
  */
 
 #define DEBUG 0
+#include <asm/div64.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/malloc.h>
@@ -59,6 +60,7 @@
 	unsigned long		 prot;
 	s32			 ptype, stype;
 	unsigned short		 id;
+	loff_t		tmp;
 
 	pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
 
@@ -147,7 +149,10 @@
 				block = AFFS_I2BSIZE(inode) - 24;
 			else
 				block = AFFS_I2BSIZE(inode);
-			inode->u.affs_i.i_lastblock = ((inode->i_size + block - 1) / block) - 1;
+			tmp = inode->i_size + block -1;
+			do_div (tmp, block);
+			tmp--;
+			inode->u.affs_i.i_lastblock = tmp;
 			break;
 		case ST_SOFTLINK:
 			inode->i_mode |= S_IFLNK;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.3.99-pre5/linux/fs/autofs/autofs_i.h	Sat Feb 26 22:31:51 2000
+++ linux/fs/autofs/autofs_i.h	Mon Apr 24 18:56:32 2000
@@ -56,13 +56,12 @@
 	struct autofs_dir_ent **back;
 	/* The following entries are for the expiry system */
 	unsigned long last_usage;
-	struct autofs_dir_ent *exp_next;
-	struct autofs_dir_ent *exp_prev;
+	struct list_head exp;
 };
 
 struct autofs_dirhash {
 	struct autofs_dir_ent *h[AUTOFS_HASH_SIZE];
-	struct autofs_dir_ent expiry_head;
+	struct list_head expiry_head;
 };
 
 struct autofs_wait_queue {
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs/dirhash.c linux/fs/autofs/dirhash.c
--- v2.3.99-pre5/linux/fs/autofs/dirhash.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/autofs/dirhash.c	Mon Apr 24 18:56:32 2000
@@ -17,17 +17,13 @@
 static void autofs_init_usage(struct autofs_dirhash *dh,
 			      struct autofs_dir_ent *ent)
 {
-	ent->exp_next = &dh->expiry_head;
-	ent->exp_prev = dh->expiry_head.exp_prev;
-	dh->expiry_head.exp_prev->exp_next = ent;
-	dh->expiry_head.exp_prev = ent;
+	list_add_tail(&ent->exp, &dh->expiry_head);
 	ent->last_usage = jiffies;
 }
 
 static void autofs_delete_usage(struct autofs_dir_ent *ent)
 {
-	ent->exp_prev->exp_next = ent->exp_next;
-	ent->exp_next->exp_prev = ent->exp_prev;
+	list_del(&ent->exp);
 }
 
 void autofs_update_usage(struct autofs_dirhash *dh,
@@ -45,12 +41,13 @@
 	struct dentry *dentry;
 	unsigned long timeout = sbi->exp_timeout;
 
-	ent = dh->expiry_head.exp_next;
-
-	if ( ent == &(dh->expiry_head) || sbi->catatonic )
-		return NULL;	/* No entries */
-
-	while ( jiffies - ent->last_usage >= timeout ) {
+	while (1) {
+		if ( list_empty(&dh->expiry_head) || sbi->catatonic )
+			return NULL;	/* No entries */
+		/* We keep the list sorted by last_usage and want old stuff */
+		ent = list_entry(dh->expiry_head.next, struct autofs_dir_ent, exp);
+		if (jiffies - ent->last_usage < timeout)
+			break;
 		/* Move to end of list in case expiry isn't desirable */
 		autofs_update_usage(dh, ent);
 
@@ -94,8 +91,7 @@
 
 void autofs_initialize_hash(struct autofs_dirhash *dh) {
 	memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
-	dh->expiry_head.exp_next = dh->expiry_head.exp_prev =
-		&dh->expiry_head;
+	INIT_LIST_HEAD(&dh->expiry_head);
 }
 
 struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name)
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.3.99-pre5/linux/fs/autofs/inode.c	Sun Mar 19 18:35:31 2000
+++ linux/fs/autofs/inode.c	Mon Apr 24 18:56:32 2000
@@ -19,19 +19,6 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
-/*
- * Dummy functions - do we ever actually want to do
- * something here?
- */
-static void autofs_put_inode(struct inode *inode)
-{
-}
-
-static void autofs_delete_inode(struct inode *inode)
-{
-	inode->i_size = 0;
-}
-
 static void autofs_put_super(struct super_block *sb)
 {
 	struct autofs_sb_info *sbi = autofs_sbi(sb);
@@ -53,13 +40,9 @@
 
 static int autofs_statfs(struct super_block *sb, struct statfs *buf);
 static void autofs_read_inode(struct inode *inode);
-static void autofs_write_inode(struct inode *inode);
 
 static struct super_operations autofs_sops = {
 	read_inode:	autofs_read_inode,
-	write_inode:	autofs_write_inode,
-	put_inode:	autofs_put_inode,
-	delete_inode:	autofs_delete_inode,
 	put_super:	autofs_put_super,
 	statfs:		autofs_statfs,
 };
@@ -137,10 +120,6 @@
 	struct autofs_sb_info *sbi;
 	int minproto, maxproto;
 
-	/* Super block already completed? */
-	if (s->s_root)
-		goto out_unlock;
-
 	sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
 	if ( !sbi )
 		goto fail_unlock;
@@ -159,25 +138,15 @@
 	s->s_blocksize_bits = 10;
 	s->s_magic = AUTOFS_SUPER_MAGIC;
 	s->s_op = &autofs_sops;
-	s->s_root = NULL;
 
-	/*
-	 * Get the root inode and dentry, but defer checking for errors.
-	 */
 	root_inode = iget(s, AUTOFS_ROOT_INO);
 	root = d_alloc_root(root_inode);
 	pipe = NULL;
 
-	/*
-	 * Check whether somebody else completed the super block.
-	 */
-	if (s->s_root)
-		goto out_dput;
-
 	if (!root)
 		goto fail_iput;
 
-	/* Can this call block? */
+	/* Can this call block?  - WTF cares? s is locked. */
 	if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
 		printk("autofs: called with bogus options\n");
 		goto fail_dput;
@@ -192,11 +161,6 @@
 
 	DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
 	pipe = fget(pipefd);
-	/*
-	 * Check whether somebody else completed the super block.
-	 */
-	if (s->s_root)
-		goto out_fput;
 	
 	if ( !pipe ) {
 		printk("autofs: could not open pipe file descriptor\n");
@@ -212,43 +176,14 @@
 	s->s_root = root;
 	return s;
 
-	/*
-	 * Success ... somebody else completed the super block for us. 
-	 */ 
-out_unlock:
-	goto out_dec;
-out_fput:
-	if (pipe)
-		fput(pipe);
-out_dput:
-	if (root)
-		dput(root);
-	else
-		iput(root_inode);
-out_dec:
-	return s;
-	
-	/*
-	 * Failure ... clear the s_dev slot and clean up.
-	 */
 fail_fput:
 	printk("autofs: pipe file descriptor does not contain proper ops\n");
-	/*
-	 * fput() can block, so we clear the super block first.
-	 */
 	fput(pipe);
-	/* fall through */
 fail_dput:
-	/*
-	 * dput() can block, so we clear the super block first.
-	 */
 	dput(root);
 	goto fail_free;
 fail_iput:
 	printk("autofs: get root dentry failed\n");
-	/*
-	 * iput() can block, so we clear the super block first.
-	 */
 	iput(root_inode);
 fail_free:
 	kfree(sbi);
@@ -260,9 +195,6 @@
 {
 	buf->f_type = AUTOFS_SUPER_MAGIC;
 	buf->f_bsize = 1024;
-	buf->f_bfree = 0;
-	buf->f_bavail = 0;
-	buf->f_ffree = 0;
 	buf->f_namelen = NAME_MAX;
 	return 0;
 }
@@ -313,8 +245,4 @@
 		inode->i_size = sl->len;
 		inode->i_nlink = 1;
 	}
-}
-
-static void autofs_write_inode(struct inode *inode)
-{
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.3.99-pre5/linux/fs/autofs/root.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/autofs/root.c	Mon Apr 24 18:56:32 2000
@@ -186,7 +186,7 @@
 	autofs_say(dentry->d_name.name,dentry->d_name.len);
 
 	if (dentry->d_name.len > NAME_MAX)
-		return ERR_PTR(-ENOENT);/* File name too long to exist */
+		return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
 
 	sbi = autofs_sbi(dir->i_sb);
 
@@ -248,9 +248,6 @@
 	if ( !autofs_oz_mode(sbi) )
 		return -EACCES;
 
-	if ( dentry->d_name.len > NAME_MAX )
-		return -ENAMETOOLONG;
-
 	if ( autofs_hash_lookup(dh, &dentry->d_name) )
 		return -EEXIST;
 
@@ -374,9 +371,6 @@
 
 	if ( !autofs_oz_mode(sbi) )
 		return -EACCES;
-
-	if ( dentry->d_name.len > NAME_MAX )
-		return -ENAMETOOLONG;
 
 	ent = autofs_hash_lookup(dh, &dentry->d_name);
 	if ( ent )
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/Makefile linux/fs/autofs4/Makefile
--- v2.3.99-pre5/linux/fs/autofs4/Makefile	Fri Jan 28 15:09:08 2000
+++ linux/fs/autofs4/Makefile	Fri Apr 21 14:41:36 2000
@@ -5,7 +5,7 @@
 #
 
 O_TARGET := autofs4.o
-O_OBJS   := inohash.o init.o inode.o root.o symlink.o waitq.o expire.o
+O_OBJS   := init.o inode.o root.o symlink.o waitq.o expire.o
 
 M_OBJS   := $(O_TARGET)
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/autofs_i.h linux/fs/autofs4/autofs_i.h
--- v2.3.99-pre5/linux/fs/autofs4/autofs_i.h	Sat Feb 26 22:31:51 2000
+++ linux/fs/autofs4/autofs_i.h	Wed Apr 26 15:30:08 2000
@@ -1,4 +1,4 @@
-/* -*- linux-c -*- ------------------------------------------------------- *
+/* -*- c -*- ------------------------------------------------------------- *
  *   
  * linux/fs/autofs/autofs_i.h
  *
@@ -57,10 +57,8 @@
 	int		flags;
 
 	struct autofs_sb_info *sbi;
-	struct list_head ino_hash;
 	unsigned long last_used;
 
-	ino_t	ino;
 	mode_t	mode;
 	size_t	size;
 
@@ -72,10 +70,6 @@
 
 #define AUTOFS_INF_EXPIRING	(1<<0) /* dentry is in the process of expiring */
 
-struct autofs_inohash {
-	struct list_head head;
-};
-
 struct autofs_wait_queue {
 	wait_queue_head_t queue;
 	struct autofs_wait_queue *next;
@@ -89,9 +83,6 @@
 	int wait_ctr;
 };
 
-#define AUTOFS_ROOT_INO		1
-#define AUTOFS_FIRST_INO	2
-
 #define AUTOFS_SBI_MAGIC 0x6d4a556d
 
 struct autofs_sb_info {
@@ -101,10 +92,8 @@
 	int catatonic;
 	int version;
 	unsigned long exp_timeout;
-	ino_t next_ino;
 	struct super_block *sb;
 	struct autofs_wait_queue *queues; /* Wait queue pointer */
-	struct autofs_inohash ihash;
 };
 
 static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb)
@@ -134,13 +123,7 @@
 		(inf != NULL && inf->flags & AUTOFS_INF_EXPIRING);
 }
 
-/* Inode hash operations */
-void autofs4_init_ihash(struct autofs_inohash *);
-void autofs4_ihash_insert(struct autofs_inohash *ih, struct autofs_info *ino);
-void autofs4_ihash_delete(struct autofs_info *ino);
-void autofs4_ihash_nuke(struct autofs_inohash *ih);
-struct autofs_info *autofs4_ihash_find(struct autofs_inohash *ih, ino_t ino);
-
+struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *);
 struct autofs_info *autofs4_init_inf(struct autofs_sb_info *, mode_t mode);
 void autofs4_free_ino(struct autofs_info *);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/expire.c linux/fs/autofs4/expire.c
--- v2.3.99-pre5/linux/fs/autofs4/expire.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/autofs4/expire.c	Fri Apr 21 14:41:36 2000
@@ -1,4 +1,4 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
+/* -*- c -*- --------------------------------------------------------------- *
  *
  * linux/fs/autofs/expire.c
  *
@@ -46,8 +46,9 @@
 		count--;
 	}
 
-	/* Mountpoints don't count */
-	if (d_mountpoint(root)) {
+	/* Mountpoints don't count (either mountee or mounter) */
+	if (d_mountpoint(root) ||
+	    root != root->d_covers) {
 		DPRINTK(("is_tree_busy: mountpoint\n"));
 		count--;
 	}
@@ -75,9 +76,11 @@
 		/* Decrement count for unused children */
 		count += (dentry->d_count - 1);
 
-		/* Mountpoints don't count */
-		if (d_mountpoint(dentry)) {
-			DPRINTK(("is_tree_busy: mountpoint\n"));
+		/* Mountpoints don't count (either mountee or mounter) */
+		if (d_mountpoint(dentry) ||
+		    dentry != dentry->d_covers) {
+			DPRINTK(("is_tree_busy: mountpoint dentry=%p covers=%p mounts=%p\n",
+				 dentry, dentry->d_covers, dentry->d_mounts));
 			adj++;
 		}
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/init.c linux/fs/autofs4/init.c
--- v2.3.99-pre5/linux/fs/autofs4/init.c	Fri Mar 10 16:40:46 2000
+++ linux/fs/autofs4/init.c	Fri Apr 21 14:41:36 2000
@@ -1,4 +1,4 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
+/* -*- c -*- --------------------------------------------------------------- *
  *
  * linux/fs/autofs/init.c
  *
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/inode.c linux/fs/autofs4/inode.c
--- v2.3.99-pre5/linux/fs/autofs4/inode.c	Fri Mar 10 16:40:46 2000
+++ linux/fs/autofs4/inode.c	Mon Apr 24 18:56:32 2000
@@ -1,4 +1,4 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
+/* -*- c -*- --------------------------------------------------------------- *
  *
  * linux/fs/autofs/inode.c
  *
@@ -41,7 +41,6 @@
 		return NULL;
 
 	ino->flags = 0;
-	ino->ino = sbi->next_ino++;
 	ino->mode = mode;
 	ino->inode = NULL;
 	ino->dentry = NULL;
@@ -50,7 +49,6 @@
 	ino->last_used = jiffies;
 
 	ino->sbi = sbi;
-	INIT_LIST_HEAD(&ino->ino_hash);
 
 	if (reinit && ino->free)
 		(ino->free)(ino);
@@ -67,7 +65,6 @@
 
 void autofs4_free_ino(struct autofs_info *ino)
 {
-	autofs4_ihash_delete(ino);
 	if (ino->dentry) {
 		ino->dentry->d_fsdata = NULL;
 		if (ino->dentry->d_inode)
@@ -79,18 +76,6 @@
 	kfree(ino);
 }
 
-/*
- * Dummy functions - do we ever actually want to do
- * something here?
- */
-static void autofs4_put_inode(struct inode *inode)
-{
-}
-
-static void autofs4_clear_inode(struct inode *inode)
-{
-}
-
 static void autofs4_put_super(struct super_block *sb)
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(sb);
@@ -105,26 +90,11 @@
 	DPRINTK(("autofs: shutting down\n"));
 }
 
-static void autofs4_umount_begin(struct super_block *sb)
-{
-	struct autofs_sb_info *sbi = autofs4_sbi(sb);
-
-	if (!sbi->catatonic)
-		autofs4_catatonic_mode(sbi);
-}
-
 static int autofs4_statfs(struct super_block *sb, struct statfs *buf);
-static void autofs4_read_inode(struct inode *inode);
-static void autofs4_write_inode(struct inode *inode);
 
 static struct super_operations autofs4_sops = {
-	read_inode:	autofs4_read_inode,
-	write_inode:	autofs4_write_inode,
-	put_inode:	autofs4_put_inode,
-	clear_inode:	autofs4_clear_inode,
 	put_super:	autofs4_put_super,
 	statfs:		autofs4_statfs,
-	umount_begin:	autofs4_umount_begin,
 };
 
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
@@ -200,8 +170,6 @@
 	if (!ino)
 		return NULL;
 
-	ino->ino = AUTOFS_ROOT_INO;
-	
 	return ino;
 }
 
@@ -215,10 +183,6 @@
 	struct autofs_sb_info *sbi;
 	int minproto, maxproto;
 
-	/* Super block already completed? */
-	if (s->s_root)
-		goto out_unlock;
-
 	sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if ( !sbi )
 		goto fail_unlock;
@@ -233,30 +197,21 @@
 	sbi->oz_pgrp = current->pgrp;
 	sbi->sb = s;
 	sbi->version = 0;
-	autofs4_init_ihash(&sbi->ihash);
 	sbi->queues = NULL;
-	sbi->next_ino = AUTOFS_FIRST_INO;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = AUTOFS_SUPER_MAGIC;
 	s->s_op = &autofs4_sops;
-	s->s_root = NULL;
 
 	/*
 	 * Get the root inode and dentry, but defer checking for errors.
 	 */
-	autofs4_ihash_insert(&sbi->ihash, autofs4_mkroot(sbi));
-
-	root_inode = iget(s, AUTOFS_ROOT_INO);
+	root_inode = autofs4_get_inode(s, autofs4_mkroot(sbi));
+	root_inode->i_op = &autofs4_root_inode_operations;
+	root_inode->i_fop = &autofs4_root_operations;
 	root = d_alloc_root(root_inode);
 	pipe = NULL;
 
-	/*
-	 * Check whether somebody else completed the super block.
-	 */
-	if (s->s_root)
-		goto out_dput;
-
 	if (!root)
 		goto fail_iput;
 
@@ -283,11 +238,6 @@
 
 	DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
 	pipe = fget(pipefd);
-	/*
-	 * Check whether somebody else completed the super block.
-	 */
-	if (s->s_root)
-		goto out_fput;
 	
 	if ( !pipe ) {
 		printk("autofs: could not open pipe file descriptor\n");
@@ -302,25 +252,9 @@
 	 */
 	s->s_root = root;
 	return s;
-
-	/*
-	 * Success ... somebody else completed the super block for us. 
-	 */ 
-out_unlock:
-	goto out_dec;
-out_fput:
-	if (pipe)
-		fput(pipe);
-out_dput:
-	if (root)
-		dput(root);
-	else
-		iput(root_inode);
-out_dec:
-	return s;
 	
 	/*
-	 * Failure ... clear the s_dev slot and clean up.
+	 * Failure ... clean up.
 	 */
 fail_fput:
 	printk("autofs: pipe file descriptor does not contain proper ops\n");
@@ -351,55 +285,44 @@
 {
 	buf->f_type = AUTOFS_SUPER_MAGIC;
 	buf->f_bsize = 1024;
-	buf->f_bfree = 0;
-	buf->f_bavail = 0;
-	buf->f_ffree = 0;
 	buf->f_namelen = NAME_MAX;
 	return 0;
 }
 
-static void autofs4_read_inode(struct inode *inode)
+struct inode *autofs4_get_inode(struct super_block *sb,
+				struct autofs_info *inf)
 {
-	struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb);
-	struct autofs_info *inf;
+	struct inode *inode = get_empty_inode();
 
-	inf = autofs4_ihash_find(&sbi->ihash, inode->i_ino);
-
-	if (inf == NULL || inf->inode != NULL)
-		return;
+	if (inode == NULL)
+		return NULL;
 
+	inf->inode = inode;
+	inode->i_sb = sb;
+	inode->i_dev = sb->s_dev;
 	inode->i_mode = inf->mode;
-	inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
-	inode->i_size = inf->size;
-
-	inode->i_blocks = 0;
-	inode->i_blksize = 0;
-	inode->i_nlink = 1;
-
-	if (inode->i_sb->s_root) {
-		inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
-		inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
+	if (sb->s_root) {
+		inode->i_uid = sb->s_root->d_inode->i_uid;
+		inode->i_gid = sb->s_root->d_inode->i_gid;
 	} else {
 		inode->i_uid = 0;
 		inode->i_gid = 0;
 	}
-
-	inf->inode = inode;
+	inode->i_size = 0;
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_rdev = 0;
+	inode->i_nlink = 1;
+	inode->i_op = NULL;
+	inode->i_fop = NULL;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 
 	if (S_ISDIR(inf->mode)) {
 		inode->i_nlink = 2;
-		if (inode->i_ino == AUTOFS_ROOT_INO) {
-			inode->i_op = &autofs4_root_inode_operations;
-			inode->i_fop = &autofs4_root_operations;
-		} else {
-			inode->i_op = &autofs4_dir_inode_operations;
-			inode->i_fop = &autofs4_dir_operations;
-		}
-	} else if (S_ISLNK(inf->mode)) {
+		inode->i_op = &autofs4_dir_inode_operations;
+		inode->i_fop = &autofs4_dir_operations;
+	} else if (S_ISLNK(inf->mode))
 		inode->i_op = &autofs4_symlink_inode_operations;
-	}
-}
 
-static void autofs4_write_inode(struct inode *inode)
-{
+	return inode;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/inohash.c linux/fs/autofs4/inohash.c
--- v2.3.99-pre5/linux/fs/autofs4/inohash.c	Fri Jan 28 15:09:08 2000
+++ linux/fs/autofs4/inohash.c	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-/*
- * "inohash" is a misnomer.  Inodes are just stored in a single list,
- * since this code is only ever asked for the most recently inserted
- * inode.
- *
- *   Copyright 1999 Jeremy Fitzhardinge <jeremy@goop.org>
- */
-
-#include "autofs_i.h"
-
-void autofs4_init_ihash(struct autofs_inohash *ih)
-{
-	INIT_LIST_HEAD(&ih->head);
-}
-
-void autofs4_ihash_insert(struct autofs_inohash *ih, 
-			  struct autofs_info *ino)
-{
-	DPRINTK(("autofs_ihash_insert: adding ino %ld\n", ino->ino));
-	
-	list_add(&ino->ino_hash, &ih->head);
-}
-
-void autofs4_ihash_delete(struct autofs_info *inf)
-{
-	DPRINTK(("autofs_ihash_delete: deleting ino %ld\n", inf->ino));
-
-	if (!list_empty(&inf->ino_hash))
-		list_del(&inf->ino_hash);
-}
-
-struct autofs_info *autofs4_ihash_find(struct autofs_inohash *ih, 
-				       ino_t inum)
-{
-	struct list_head *tmp;
-
-	for(tmp = ih->head.next;
-	    tmp != &ih->head;
-	    tmp = tmp->next) {
-		struct autofs_info *ino = list_entry(tmp, struct autofs_info, ino_hash);
-		if (ino->ino == inum) {
-			DPRINTK(("autofs_ihash_find: found %ld -> %p\n",
-				 inum, ino));
-			return ino;
-		}
-	}
-	DPRINTK(("autofs_ihash_find: didn't find %ld\n", inum));
-	return NULL;
-}
-
-void autofs4_ihash_nuke(struct autofs_inohash *ih)
-{
-	struct list_head *tmp = ih->head.next;
-	struct list_head *next;
-		
-	for(; tmp != &ih->head; tmp = next) {
-		struct autofs_info *ino;
-
-		next = tmp->next;
-
-		ino = list_entry(tmp, struct autofs_info, ino_hash);
-
-		DPRINTK(("autofs_ihash_nuke: nuking %ld\n", ino->ino));
-		autofs4_free_ino(ino);
-	}
-	INIT_LIST_HEAD(&ih->head);
-}
-
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/root.c linux/fs/autofs4/root.c
--- v2.3.99-pre5/linux/fs/autofs4/root.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/autofs4/root.c	Mon Apr 24 18:56:32 2000
@@ -1,4 +1,4 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
+/* -*- c -*- --------------------------------------------------------------- *
  *
  * linux/fs/autofs/root.c
  *
@@ -87,7 +87,7 @@
 		filp->f_pos = ++nr;
 		/* fall through */
 	case 1:
-		if (filldir(dirent, "..", 2, nr, dentry->d_covers->d_parent->d_inode->i_ino) < 0)
+		if (filldir(dirent, "..", 2, nr, dentry->d_parent->d_inode->i_ino) < 0)
 			return 0;
 		filp->f_pos = ++nr;
 		/* fall through */
@@ -175,7 +175,7 @@
 			/* Return a negative dentry, but leave it "pending" */
 			return 1;
 		}
-		status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT);
+		/* status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT); */
 	}
 
 	/* If this is an unused directory that isn't a mount point,
@@ -230,7 +230,7 @@
 	    list_empty(&dentry->d_subdirs)) {
 		DPRINTK(("autofs_root_revalidate: dentry=%p %.*s, emptydir\n",
 			 dentry, dentry->d_name.len, dentry->d_name.name));
-		if (autofs4_oz_mode(sbi))
+		if (oz_mode)
 			return 1;
 		else
 			return try_to_fill_dentry(dentry, dir->i_sb, sbi);
@@ -305,7 +305,7 @@
 		 dentry->d_name.len, dentry->d_name.name));
 
 	if (dentry->d_name.len > NAME_MAX)
-		return ERR_PTR(-ENOENT);/* File name too long to exist */
+		return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
 
 	sbi = autofs4_sbi(dir->i_sb);
 
@@ -323,12 +323,10 @@
 	 *
 	 * We need to do this before we release the directory semaphore.
 	 */
-	if (dir->i_ino == AUTOFS_ROOT_INO)
-		dentry->d_op = &autofs4_root_dentry_operations;
-	else
-		dentry->d_op = &autofs4_dentry_operations;
+	dentry->d_op = &autofs4_root_dentry_operations;
 
-	dentry->d_flags |= DCACHE_AUTOFS_PENDING;
+	if (!oz_mode)
+		dentry->d_flags |= DCACHE_AUTOFS_PENDING;
 	dentry->d_fsdata = NULL;
 	d_add(dentry, NULL);
 
@@ -371,18 +369,9 @@
 	DPRINTK(("autofs_dir_symlink: %s <- %.*s\n", symname, 
 		 dentry->d_name.len, dentry->d_name.name));
 
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOTDIR;
-
 	if (!autofs4_oz_mode(sbi))
 		return -EACCES;
 
-	if (dentry->d_name.len > NAME_MAX)
-		return -ENAMETOOLONG;
-
-	if (dentry->d_inode != NULL)
-		return -EEXIST;
-
 	ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555);
 	if (ino == NULL)
 		return -ENOSPC;
@@ -397,11 +386,10 @@
 
 	strcpy(cp, symname);
 
-	autofs4_ihash_insert(&sbi->ihash, ino);
-	inode = iget(dir->i_sb,ino->ino);
+	inode = autofs4_get_inode(dir->i_sb, ino);
 	d_instantiate(dentry, inode);
 
-	if (dir->i_ino == AUTOFS_ROOT_INO)
+	if (dir == dir->i_sb->s_root->d_inode)
 		dentry->d_op = &autofs4_root_dentry_operations;
 	else
 		dentry->d_op = &autofs4_dentry_operations;
@@ -434,12 +422,6 @@
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOTDIR;
-
-	if (dentry->d_inode == NULL)
-		return -ENOENT;
 	
 	/* This allows root to remove symlinks */
 	if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
@@ -464,12 +446,6 @@
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOTDIR;
-
-	if (dentry->d_inode == NULL)
-		return -ENOENT;
 	
 	if (!autofs4_oz_mode(sbi))
 		return -EACCES;
@@ -501,18 +477,9 @@
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
 	struct inode *inode;
 
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOTDIR;
-
 	if ( !autofs4_oz_mode(sbi) )
 		return -EACCES;
 
-	if ( dentry->d_inode != NULL )
-		return -EEXIST;
-	
-	if ( dentry->d_name.len > NAME_MAX )
-		return -ENAMETOOLONG;
-
 	DPRINTK(("autofs_dir_mkdir: dentry %p, creating %.*s\n",
 		 dentry, dentry->d_name.len, dentry->d_name.name));
 
@@ -520,12 +487,10 @@
 	if (ino == NULL)
 		return -ENOSPC;
 
-	autofs4_ihash_insert(&sbi->ihash, ino);
-
-	inode = iget(dir->i_sb, ino->ino);
+	inode = autofs4_get_inode(dir->i_sb, ino);
 	d_instantiate(dentry, inode);
 
-	if (dir->i_ino == AUTOFS_ROOT_INO)
+	if (dir == dir->i_sb->s_root->d_inode)
 		dentry->d_op = &autofs4_root_dentry_operations;
 	else
 		dentry->d_op = &autofs4_dentry_operations;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/symlink.c linux/fs/autofs4/symlink.c
--- v2.3.99-pre5/linux/fs/autofs4/symlink.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/autofs4/symlink.c	Fri Apr 21 14:41:36 2000
@@ -1,4 +1,4 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
+/* -*- c -*- --------------------------------------------------------------- *
  *
  * linux/fs/autofs/symlink.c
  *
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/autofs4/waitq.c linux/fs/autofs4/waitq.c
--- v2.3.99-pre5/linux/fs/autofs4/waitq.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/autofs4/waitq.c	Fri Apr 21 14:41:36 2000
@@ -1,4 +1,4 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
+/* -*- c -*- --------------------------------------------------------------- *
  *
  * linux/fs/autofs/waitq.c
  *
@@ -45,7 +45,6 @@
 		sbi->pipe = NULL;
 	}
 
-	autofs4_ihash_nuke(&sbi->ihash);
 	shrink_dcache_sb(sbi->sb);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/bad_inode.c linux/fs/bad_inode.c
--- v2.3.99-pre5/linux/fs/bad_inode.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/bad_inode.c	Wed Apr 12 09:47:28 2000
@@ -79,8 +79,8 @@
  *	@inode: Inode to mark bad
  *
  *	When an inode cannot be read due to a media or remote network
- *	failure this function makes the inode 'bad' and causes I/O operations
- *	on it to fail from this point on
+ *	failure this function makes the inode "bad" and causes I/O operations
+ *	on it to fail from this point on.
  */
  
 void make_bad_inode(struct inode * inode) 
@@ -101,7 +101,7 @@
  *	is_bad_inode - is an inode errored
  *	@inode: inode to test
  *
- *	Returns true if the inode in question has been marked as bad
+ *	Returns true if the inode in question has been marked as bad.
  */
  
 int is_bad_inode(struct inode * inode) 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/bfs/file.c linux/fs/bfs/file.c
--- v2.3.99-pre5/linux/fs/bfs/file.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/bfs/file.c	Tue Apr 25 17:28:56 2000
@@ -127,7 +127,7 @@
 	return err;
 }
 
-static int bfs_writepage(struct dentry *dentry, struct page *page)
+static int bfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page, bfs_get_block);
 }
@@ -150,6 +150,7 @@
 struct address_space_operations bfs_aops = {
 	readpage:	bfs_readpage,
 	writepage:	bfs_writepage,
+	sync_page:	block_sync_page,
 	prepare_write:	bfs_prepare_write,
 	commit_write:	generic_commit_write,
 	bmap:		bfs_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.99-pre5/linux/fs/binfmt_aout.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/binfmt_aout.c	Thu Apr 13 08:11:48 2000
@@ -252,7 +252,6 @@
 static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
 	struct exec ex;
-	int fd;
 	unsigned long error;
 	unsigned long fd_offset;
 	unsigned long rlim;
@@ -284,11 +283,14 @@
 		return retval;
 
 	/* OK, This is the point of no return */
-	current->personality = PER_LINUX;
-
-#if defined(__sparc__) && !defined(__sparc_v9__)
+#if !defined(__sparc__)
+	set_personality(PER_LINUX);
+#else
+	set_personality(PER_SUNOS);
+#if !defined(__sparc_v9__)
 	memcpy(&current->thread.core_exec, &ex, sizeof(struct exec));
 #endif
+#endif
 
 	current->mm->end_code = ex.a_text +
 		(current->mm->start_code = N_TXTADDR(ex));
@@ -341,12 +343,6 @@
 			error_time2 = jiffies;
 		}
 
-		fd = get_unused_fd();
-		if (fd < 0)
-			return fd;
-		get_file(bprm->file);
-		fd_install(fd, bprm->file);
-
 		if ((fd_offset & ~PAGE_MASK) != 0 &&
 		    (jiffies-error_time) > 5*HZ)
 		{
@@ -358,7 +354,6 @@
 
 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
 			loff_t pos = fd_offset;
-			sys_close(fd);
 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 					ex.a_text+ex.a_data, &pos);
@@ -374,7 +369,6 @@
 			fd_offset);
 
 		if (error != N_TXTADDR(ex)) {
-			sys_close(fd);
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
@@ -383,20 +377,13 @@
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
-		sys_close(fd);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
 	}
 beyond_if:
-	put_exec_domain(current->exec_domain);
-	if (current->binfmt && current->binfmt->module)
-		__MOD_DEC_USE_COUNT(current->binfmt->module);
-	current->exec_domain = lookup_exec_domain(current->personality);
-	current->binfmt = &aout_format;
-	if (current->binfmt && current->binfmt->module)
-		__MOD_INC_USE_COUNT(current->binfmt->module);
+	set_binfmt(&aout_format);
 
 	set_brk(current->mm->start_brk, current->mm->brk);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.99-pre5/linux/fs/binfmt_elf.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/binfmt_elf.c	Mon Apr 24 17:57:42 2000
@@ -479,10 +479,22 @@
 #ifdef __sparc__
 			if (ibcs2_interpreter) {
 				unsigned long old_pers = current->personality;
-					
-				current->personality = PER_SVR4;
+				struct exec_domain *old_domain = current->exec_domain;
+				struct exec_domain *new_domain;
+				struct fs_struct *old_fs = current->fs, *new_fs;
+				get_exec_domain(old_domain);
+				atomic_inc(&old_fs->count);
+
+				set_personality(PER_SVR4);
 				interpreter = open_exec(elf_interpreter);
+
+				new_domain = current->exec_domain;
+				new_fs = current->fs;
 				current->personality = old_pers;
+				current->exec_domain = old_domain;
+				current->fs = old_fs;
+				put_exec_domain(new_domain);
+				put_fs_struct(new_fs);
 			} else
 #endif
 			{
@@ -668,19 +680,8 @@
 	if (interpreter_type != INTERPRETER_AOUT)
 		sys_close(elf_exec_fileno);
 
-	put_exec_domain(current->exec_domain);
-	if (current->binfmt && current->binfmt->module)
-		__MOD_DEC_USE_COUNT(current->binfmt->module);
-	current->exec_domain = lookup_exec_domain(current->personality);
-	current->binfmt = &elf_format;
-	if (current->binfmt && current->binfmt->module)
-		__MOD_INC_USE_COUNT(current->binfmt->module);
+	set_binfmt(&elf_format);
 
-#ifndef VM_STACK_FLAGS
-	lock_kernel();
-	current->executable = dget(bprm->file->f_dentry);
-	unlock_kernel();
-#endif
 	compute_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
 	bprm->p = (unsigned long)
@@ -962,7 +963,7 @@
 #undef DUMP_SEEK
 
 #define DUMP_WRITE(addr, nr)	\
-	if (!dump_write(file, (addr), (nr))) \
+	if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
 		goto end_coredump;
 #define DUMP_SEEK(off)	\
 	if (!dump_seek(file, (off))) \
@@ -979,8 +980,8 @@
 	int has_dumped = 0;
 	mm_segment_t fs;
 	int segs;
+	size_t size = 0;
 	int i;
-	size_t size;
 	struct vm_area_struct *vma;
 	struct elfhdr elf;
 	off_t offset = 0, dataoff;
@@ -991,24 +992,10 @@
 	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
 
-	/* Count what's needed to dump, up to the limit of coredump size */
-	segs = 0;
-	size = 0;
-	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
-		if (maydump(vma))
-		{
-			unsigned long sz = vma->vm_end-vma->vm_start;
-
-			if (size+sz >= limit)
-				break;
-			else
-				size += sz;
-		}
+	segs = current->mm->map_count;
 
-		segs++;
-	}
 #ifdef DEBUG
-	printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
+	printk("elf_core_dump: %d segs %lu limit\n", segs, limit);
 #endif
 
 	/* Set up header */
@@ -1165,13 +1152,10 @@
 	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
 	/* Write program headers for segments dump */
-	for(vma = current->mm->mmap, i = 0;
-		i < segs && vma != NULL; vma = vma->vm_next) {
+	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
 		struct elf_phdr phdr;
 		size_t sz;
 
-		i++;
-
 		sz = vma->vm_end - vma->vm_start;
 
 		phdr.p_type = PT_LOAD;
@@ -1197,19 +1181,36 @@
 
 	DUMP_SEEK(dataoff);
 
-	for(i = 0, vma = current->mm->mmap;
-	    i < segs && vma != NULL;
-	    vma = vma->vm_next) {
-		unsigned long addr = vma->vm_start;
-		unsigned long len = vma->vm_end - vma->vm_start;
+	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+		unsigned long addr;
 
-		i++;
 		if (!maydump(vma))
 			continue;
 #ifdef DEBUG
 		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
 #endif
-		DUMP_WRITE((void *)addr, len);
+		for (addr = vma->vm_start;
+		     addr < vma->vm_end;
+		     addr += PAGE_SIZE) {
+			pgd_t *pgd;
+			pmd_t *pmd;
+			pte_t *pte;
+
+			pgd = pgd_offset(vma->vm_mm, addr);
+			pmd = pmd_alloc(pgd, addr);
+	
+			if (!pmd)
+				goto end_coredump;
+			pte = pte_alloc(pmd, addr);
+			if (!pte)
+				goto end_coredump;
+			if (!pte_present(*pte) &&
+			    pte_none(*pte)) {
+				DUMP_SEEK (file->f_pos + PAGE_SIZE);
+			} else {
+				DUMP_WRITE((void*)addr, PAGE_SIZE);
+			}
+		}
 	}
 
 	if ((off_t) file->f_pos != offset) {
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.3.99-pre5/linux/fs/block_dev.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/block_dev.c	Wed Apr 12 09:47:28 2000
@@ -313,7 +313,7 @@
  *	since the vma has no handle.
  */
  
-static int block_fsync(struct file *filp, struct dentry *dentry)
+int block_fsync(struct file *filp, struct dentry *dentry)
 {
 	return fsync_dev(dentry->d_inode->i_rdev);
 }
@@ -650,7 +650,7 @@
 	return ret;
 }
 
-static int blkdev_close(struct inode * inode, struct file * filp)
+int blkdev_close(struct inode * inode, struct file * filp)
 {
 	return blkdev_put(inode->i_bdev, BDEV_FILE);
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.99-pre5/linux/fs/buffer.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/buffer.c	Tue Apr 25 17:28:55 2000
@@ -28,6 +28,7 @@
 
 /* async buffer flushing, 1999 Andrea Arcangeli <andrea@suse.de> */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/malloc.h>
@@ -1755,8 +1756,6 @@
 
 	kiobuf = bh->b_kiobuf;
 	unlock_buffer(bh);
-	
-	kiobuf = bh->b_kiobuf;
 	end_kio_request(kiobuf, uptodate);
 }
 
@@ -2192,7 +2191,7 @@
 
 void show_buffers(void)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	struct buffer_head * bh;
 	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
 	int protected = 0;
@@ -2203,7 +2202,7 @@
 	printk("Buffer memory:   %6dkB\n",
 			atomic_read(&buffermem_pages) << (PAGE_SHIFT-10));
 
-#ifdef __SMP__ /* trylock does nothing on UP and so we could deadlock */
+#ifdef CONFIG_SMP /* trylock does nothing on UP and so we could deadlock */
 	if (!spin_trylock(&lru_list_lock))
 		return;
 	for(nlist = 0; nlist < NR_LIST; nlist++) {
@@ -2412,6 +2411,12 @@
 
 	flush_dirty_buffers(1);
 	/* must really sync all the active I/O request to disk here */
+	run_task_queue(&tq_disk);
+	return 0;
+}
+
+int block_sync_page(struct page *page)
+{
 	run_task_queue(&tq_disk);
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/adler32.c linux/fs/cramfs/inflate/adler32.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/adler32.c	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/adler32.c	Wed Apr 12 09:47:29 2000
@@ -18,7 +18,7 @@
 #define DO16(buf)   DO8(buf,0); DO8(buf,8);
 
 /* ========================================================================= */
-uLong ZEXPORT adler32(adler, buf, len)
+uLong ZEXPORT cramfs_adler32(adler, buf, len)
     uLong adler;
     const Bytef *buf;
     uInt len;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/infblock.c linux/fs/cramfs/inflate/infblock.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/infblock.c	Tue Jan  4 13:57:17 2000
+++ linux/fs/cramfs/inflate/infblock.c	Wed Apr 12 09:47:29 2000
@@ -65,7 +65,7 @@
  */
 
 
-void inflate_blocks_reset(s, z, c)
+void cramfs_inflate_blocks_reset(s, z, c)
 inflate_blocks_statef *s;
 z_streamp z;
 uLongf *c;
@@ -73,7 +73,7 @@
   if (c != Z_NULL)
     *c = s->check;
   if (s->mode == CODES)
-    inflate_codes_free(s->sub.decode.codes, z);
+    cramfs_inflate_codes_free(s->sub.decode.codes, z);
   s->mode = TYPE;
   s->bitk = 0;
   s->bitb = 0;
@@ -83,7 +83,7 @@
 }
 
 
-inflate_blocks_statef *inflate_blocks_new(z, c, w)
+inflate_blocks_statef *cramfs_inflate_blocks_new(z, c, w)
 z_streamp z;
 check_func c;
 uInt w;
@@ -99,12 +99,12 @@
   s->end = s->window + w;
   s->checkfn = c;
   s->mode = TYPE;
-  inflate_blocks_reset(s, z, Z_NULL);
+  cramfs_inflate_blocks_reset(s, z, Z_NULL);
   return s;
 }
 
 
-int inflate_blocks(s, z, r)
+int cramfs_inflate_blocks(s, z, r)
 inflate_blocks_statef *s;
 z_streamp z;
 int r;
@@ -140,8 +140,8 @@
             uInt bl, bd;
             inflate_huft *tl, *td;
 
-            inflate_trees_fixed(&bl, &bd, &tl, &td, z);
-            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            cramfs_inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = cramfs_inflate_codes_new(bl, bd, tl, td, z);
             if (s->sub.decode.codes == Z_NULL)
             {
               r = Z_MEM_ERROR;
@@ -219,7 +219,7 @@
       while (s->sub.trees.index < 19)
         s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
       s->sub.trees.bb = 7;
-      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+      t = cramfs_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
                              &s->sub.trees.tb, s->hufts, z);
       if (t != Z_OK)
       {
@@ -239,7 +239,7 @@
 
         t = s->sub.trees.bb;
         NEEDBITS(t)
-        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        h = s->sub.trees.tb + ((uInt)b & cramfs_inflate_mask[t]);
         t = h->bits;
         c = h->base;
         if (c < 16)
@@ -253,7 +253,7 @@
           j = c == 18 ? 11 : 3;
           NEEDBITS(t + i)
           DUMPBITS(t)
-          j += (uInt)b & inflate_mask[i];
+          j += (uInt)b & cramfs_inflate_mask[i];
           DUMPBITS(i)
           i = s->sub.trees.index;
           t = s->sub.trees.table;
@@ -281,7 +281,7 @@
         bl = 9;         /* must be <= 9 for lookahead assumptions */
         bd = 6;         /* must be <= 9 for lookahead assumptions */
         t = s->sub.trees.table;
-        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+        t = cramfs_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
                                   s->sub.trees.blens, &bl, &bd, &tl, &td,
                                   s->hufts, z);
         if (t != Z_OK)
@@ -291,7 +291,7 @@
           r = t;
           LEAVE
         }
-        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        if ((c = cramfs_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
         {
           r = Z_MEM_ERROR;
           LEAVE
@@ -301,10 +301,10 @@
       s->mode = CODES;
     case CODES:
       UPDATE
-      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
-        return inflate_flush(s, z, r);
+      if ((r = cramfs_inflate_codes(s, z, r)) != Z_STREAM_END)
+        return cramfs_inflate_flush(s, z, r);
       r = Z_OK;
-      inflate_codes_free(s->sub.decode.codes, z);
+      cramfs_inflate_codes_free(s->sub.decode.codes, z);
       LOAD
       if (!s->last)
       {
@@ -330,16 +330,16 @@
 }
 
 
-int inflate_blocks_free(s, z)
+int cramfs_inflate_blocks_free(s, z)
 inflate_blocks_statef *s;
 z_streamp z;
 {
-  inflate_blocks_reset(s, z, Z_NULL);
+  cramfs_inflate_blocks_reset(s, z, Z_NULL);
   return Z_OK;
 }
 
 
-void inflate_set_dictionary(s, d, n)
+void cramfs_inflate_set_dictionary(s, d, n)
 inflate_blocks_statef *s;
 const Bytef *d;
 uInt  n;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/infblock.h linux/fs/cramfs/inflate/infblock.h
--- v2.3.99-pre5/linux/fs/cramfs/inflate/infblock.h	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/infblock.h	Wed Apr 12 09:47:29 2000
@@ -11,26 +11,26 @@
 struct inflate_blocks_state;
 typedef struct inflate_blocks_state FAR inflate_blocks_statef;
 
-extern inflate_blocks_statef * inflate_blocks_new OF((
+extern inflate_blocks_statef * cramfs_inflate_blocks_new OF((
     z_streamp z,
     check_func c,               /* check function */
     uInt w));                   /* window size */
 
-extern int inflate_blocks OF((
+extern int cramfs_inflate_blocks OF((
     inflate_blocks_statef *,
     z_streamp ,
     int));                      /* initial return code */
 
-extern void inflate_blocks_reset OF((
+extern void cramfs_inflate_blocks_reset OF((
     inflate_blocks_statef *,
     z_streamp ,
     uLongf *));                  /* check value on output */
 
-extern int inflate_blocks_free OF((
+extern int cramfs_inflate_blocks_free OF((
     inflate_blocks_statef *,
     z_streamp));
 
-extern void inflate_set_dictionary OF((
+extern void cramfs_inflate_set_dictionary OF((
     inflate_blocks_statef *s,
     const Bytef *d,  /* dictionary */
     uInt  n));       /* dictionary length */
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/infcodes.c linux/fs/cramfs/inflate/infcodes.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/infcodes.c	Tue Jan  4 13:57:17 2000
+++ linux/fs/cramfs/inflate/infcodes.c	Wed Apr 12 09:47:29 2000
@@ -56,7 +56,7 @@
 };
 
 
-inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+inflate_codes_statef *cramfs_inflate_codes_new(bl, bd, tl, td, z)
 uInt bl, bd;
 inflate_huft *tl;
 inflate_huft *td; /* need separate declaration for Borland C++ */
@@ -77,7 +77,7 @@
 }
 
 
-int inflate_codes(s, z, r)
+int cramfs_inflate_codes(s, z, r)
 inflate_blocks_statef *s;
 z_streamp z;
 int r;
@@ -105,7 +105,7 @@
       if (m >= 258 && n >= 10)
       {
         UPDATE
-        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        r = cramfs_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
         LOAD
         if (r != Z_OK)
         {
@@ -120,7 +120,7 @@
     case LEN:           /* i: get length/literal/eob next */
       j = c->sub.code.need;
       NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      t = c->sub.code.tree + ((uInt)b & cramfs_inflate_mask[j]);
       DUMPBITS(t->bits)
       e = (uInt)(t->exop);
       if (e == 0)               /* literal */
@@ -154,7 +154,7 @@
     case LENEXT:        /* i: getting length extra (have base) */
       j = c->sub.copy.get;
       NEEDBITS(j)
-      c->len += (uInt)b & inflate_mask[j];
+      c->len += (uInt)b & cramfs_inflate_mask[j];
       DUMPBITS(j)
       c->sub.code.need = c->dbits;
       c->sub.code.tree = c->dtree;
@@ -162,7 +162,7 @@
     case DIST:          /* i: get distance next */
       j = c->sub.code.need;
       NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      t = c->sub.code.tree + ((uInt)b & cramfs_inflate_mask[j]);
       DUMPBITS(t->bits)
       e = (uInt)(t->exop);
       if (e & 16)               /* distance */
@@ -185,7 +185,7 @@
     case DISTEXT:       /* i: getting distance extra */
       j = c->sub.copy.get;
       NEEDBITS(j)
-      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      c->sub.copy.dist += (uInt)b & cramfs_inflate_mask[j];
       DUMPBITS(j)
       c->mode = COPY;
     case COPY:          /* o: copying bytes in window, waiting for space */
@@ -240,7 +240,7 @@
 }
 
 
-void inflate_codes_free(c, z)
+void cramfs_inflate_codes_free(c, z)
 inflate_codes_statef *c;
 z_streamp z;
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/infcodes.h linux/fs/cramfs/inflate/infcodes.h
--- v2.3.99-pre5/linux/fs/cramfs/inflate/infcodes.h	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/infcodes.h	Wed Apr 12 09:47:29 2000
@@ -11,17 +11,17 @@
 struct inflate_codes_state;
 typedef struct inflate_codes_state FAR inflate_codes_statef;
 
-extern inflate_codes_statef *inflate_codes_new OF((
+extern inflate_codes_statef *cramfs_inflate_codes_new OF((
     uInt, uInt,
     inflate_huft *, inflate_huft *,
     z_streamp ));
 
-extern int inflate_codes OF((
+extern int cramfs_inflate_codes OF((
     inflate_blocks_statef *,
     z_streamp ,
     int));
 
-extern void inflate_codes_free OF((
+extern void cramfs_inflate_codes_free OF((
     inflate_codes_statef *,
     z_streamp ));
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/inffast.c linux/fs/cramfs/inflate/inffast.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/inffast.c	Tue Jan  4 13:57:17 2000
+++ linux/fs/cramfs/inflate/inffast.c	Wed Apr 12 09:47:29 2000
@@ -25,7 +25,7 @@
    at least ten.  The ten bytes are six bytes for the longest length/
    distance pair plus four bytes for overloading the bit buffer. */
 
-int inflate_fast(bl, bd, tl, td, s, z)
+int cramfs_inflate_fast(bl, bd, tl, td, s, z)
 uInt bl, bd;
 inflate_huft *tl;
 inflate_huft *td; /* need separate declaration for Borland C++ */
@@ -50,8 +50,8 @@
   LOAD
 
   /* initialize masks */
-  ml = inflate_mask[bl];
-  md = inflate_mask[bd];
+  ml = cramfs_inflate_mask[bl];
+  md = cramfs_inflate_mask[bd];
 
   /* do until not enough input or output space for fast loop */
   do {                          /* assume called with m >= 258 && n >= 10 */
@@ -70,7 +70,7 @@
       {
         /* get extra bits for length */
         e &= 15;
-        c = t->base + ((uInt)b & inflate_mask[e]);
+        c = t->base + ((uInt)b & cramfs_inflate_mask[e]);
         DUMPBITS(e)
 
         /* decode distance base of block to copy */
@@ -83,7 +83,7 @@
             /* get extra bits to add to distance base */
             e &= 15;
             GRABBITS(e)         /* get extra bits (up to 13) */
-            d = t->base + ((uInt)b & inflate_mask[e]);
+            d = t->base + ((uInt)b & cramfs_inflate_mask[e]);
             DUMPBITS(e)
 
             /* do the copy */
@@ -115,7 +115,7 @@
           else if ((e & 64) == 0)
           {
             t += t->base;
-            e = (t += ((uInt)b & inflate_mask[e]))->exop;
+            e = (t += ((uInt)b & cramfs_inflate_mask[e]))->exop;
           }
           else
           {
@@ -130,7 +130,7 @@
       if ((e & 64) == 0)
       {
         t += t->base;
-        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+        if ((e = (t += ((uInt)b & cramfs_inflate_mask[e]))->exop) == 0)
         {
           DUMPBITS(t->bits)
           *q++ = (Byte)t->base;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/inffast.h linux/fs/cramfs/inflate/inffast.h
--- v2.3.99-pre5/linux/fs/cramfs/inflate/inffast.h	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/inffast.h	Wed Apr 12 09:47:29 2000
@@ -8,7 +8,7 @@
    subject to change. Applications should only use zlib.h.
  */
 
-extern int inflate_fast OF((
+extern int cramfs_inflate_fast OF((
     uInt,
     uInt,
     inflate_huft *,
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/inflate.c linux/fs/cramfs/inflate/inflate.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/inflate.c	Tue Jan  4 13:57:17 2000
+++ linux/fs/cramfs/inflate/inflate.c	Wed Apr 12 09:47:29 2000
@@ -50,7 +50,7 @@
 };
 
 
-int ZEXPORT inflateReset(z)
+int ZEXPORT cramfs_inflateReset(z)
 z_streamp z;
 {
   if (z == Z_NULL || z->state == Z_NULL)
@@ -58,24 +58,24 @@
   z->total_in = z->total_out = 0;
   z->msg = Z_NULL;
   z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-  inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  cramfs_inflate_blocks_reset(z->state->blocks, z, Z_NULL);
   return Z_OK;
 }
 
 
-int ZEXPORT inflateEnd(z)
+int ZEXPORT cramfs_inflateEnd(z)
 z_streamp z;
 {
   if (z == Z_NULL || z->state == Z_NULL)
     return Z_STREAM_ERROR;
   if (z->state->blocks != Z_NULL)
-    inflate_blocks_free(z->state->blocks, z);
+    cramfs_inflate_blocks_free(z->state->blocks, z);
   z->state = Z_NULL;
   return Z_OK;
 }
 
 
-int ZEXPORT inflateInit2_(z, w, version, stream_size)
+int ZEXPORT cramfs_inflateInit2_(z, w, version, stream_size)
 z_streamp z;
 int w;
 const char *version;
@@ -105,39 +105,39 @@
   /* set window size */
   if (w < 8 || w > 15)
   {
-    inflateEnd(z);
+    cramfs_inflateEnd(z);
     return Z_STREAM_ERROR;
   }
   z->state->wbits = (uInt)w;
 
   /* create inflate_blocks state */
   if ((z->state->blocks =
-      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      cramfs_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : cramfs_adler32, (uInt)1 << w))
       == Z_NULL)
   {
-    inflateEnd(z);
+    cramfs_inflateEnd(z);
     return Z_MEM_ERROR;
   }
 
   /* reset state */
-  inflateReset(z);
+  cramfs_inflateReset(z);
   return Z_OK;
 }
 
 
-int ZEXPORT inflateInit_(z, version, stream_size)
+int ZEXPORT cramfs_inflateInit_(z, version, stream_size)
 z_streamp z;
 const char *version;
 int stream_size;
 {
-  return inflateInit2_(z, DEF_WBITS, version, stream_size);
+  return cramfs_inflateInit2_(z, DEF_WBITS, version, stream_size);
 }
 
 
 #define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
 #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
 
-int ZEXPORT inflate(z, f)
+int ZEXPORT cramfs_inflate(z, f)
 z_streamp z;
 int f;
 {
@@ -207,7 +207,7 @@
       z->state->sub.marker = 0;       /* can try inflateSync */
       return Z_STREAM_ERROR;
     case BLOCKS:
-      r = inflate_blocks(z->state->blocks, z, r);
+      r = cramfs_inflate_blocks(z->state->blocks, z, r);
       if (r == Z_DATA_ERROR)
       {
         z->state->mode = BAD;
@@ -219,7 +219,7 @@
       if (r != Z_STREAM_END)
         return r;
       r = f;
-      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      cramfs_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
       if (z->state->nowrap)
       {
         z->state->mode = DONE;
@@ -263,7 +263,7 @@
 }
 
 
-int ZEXPORT inflateSync(z)
+int ZEXPORT cramfs_inflateSync(z)
 z_streamp z;
 {
   uInt n;       /* number of bytes to look at */
@@ -307,7 +307,7 @@
   if (m != 4)
     return Z_DATA_ERROR;
   r = z->total_in;  w = z->total_out;
-  inflateReset(z);
+  cramfs_inflateReset(z);
   z->total_in = r;  z->total_out = w;
   z->state->mode = BLOCKS;
   return Z_OK;
@@ -321,7 +321,7 @@
  * decompressing, PPP checks that at the end of input packet, inflate is
  * waiting for these length bytes.
  */
-int ZEXPORT inflateSyncPoint(z)
+int ZEXPORT cramfs_inflateSyncPoint(z)
 z_streamp z;
 {
   if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/inftrees.c linux/fs/cramfs/inflate/inftrees.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/inftrees.c	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/inftrees.c	Wed Apr 12 09:47:29 2000
@@ -6,7 +6,7 @@
 #include "zutil.h"
 #include "inftrees.h"
 
-const char inflate_copyright[] =
+static const char inflate_copyright[] =
    " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
 /*
   If you use the zlib library in a product, an acknowledgment is welcome
@@ -287,7 +287,7 @@
 }
 
 
-int inflate_trees_bits(c, bb, tb, hp, z)
+int cramfs_inflate_trees_bits(c, bb, tb, hp, z)
 uIntf *c;               /* 19 code lengths */
 uIntf *bb;              /* bits tree desired/actual depth */
 inflate_huft * FAR *tb; /* bits tree result */
@@ -312,7 +312,7 @@
   return r;
 }
 
-int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+int cramfs_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
 uInt nl;                /* number of literal/length codes */
 uInt nd;                /* number of distance codes */
 uIntf *c;               /* that many (total) code lengths */
@@ -377,7 +377,7 @@
 #include "inffixed.h"
 
 
-int inflate_trees_fixed(bl, bd, tl, td, z)
+int cramfs_inflate_trees_fixed(bl, bd, tl, td, z)
 uIntf *bl;               /* literal desired/actual bit depth */
 uIntf *bd;               /* distance desired/actual bit depth */
 inflate_huft * FAR *tl;  /* literal/length tree result */
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/inftrees.h linux/fs/cramfs/inflate/inftrees.h
--- v2.3.99-pre5/linux/fs/cramfs/inflate/inftrees.h	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/inftrees.h	Wed Apr 12 09:47:29 2000
@@ -32,14 +32,14 @@
    value below is more than safe. */
 #define MANY 1440
 
-extern int inflate_trees_bits OF((
+extern int cramfs_inflate_trees_bits OF((
     uIntf *,                    /* 19 code lengths */
     uIntf *,                    /* bits tree desired/actual depth */
     inflate_huft * FAR *,       /* bits tree result */
     inflate_huft *,             /* space for trees */
     z_streamp));                /* for messages */
 
-extern int inflate_trees_dynamic OF((
+extern int cramfs_inflate_trees_dynamic OF((
     uInt,                       /* number of literal/length codes */
     uInt,                       /* number of distance codes */
     uIntf *,                    /* that many (total) code lengths */
@@ -50,7 +50,7 @@
     inflate_huft *,             /* space for trees */
     z_streamp));                /* for messages */
 
-extern int inflate_trees_fixed OF((
+extern int cramfs_inflate_trees_fixed OF((
     uIntf *,                    /* literal desired/actual bit depth */
     uIntf *,                    /* distance desired/actual bit depth */
     inflate_huft * FAR *,       /* literal/length tree result */
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/infutil.c linux/fs/cramfs/inflate/infutil.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/infutil.c	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/infutil.c	Wed Apr 12 09:47:29 2000
@@ -12,7 +12,7 @@
 struct inflate_codes_state {int dummy;}; /* for buggy compilers */
 
 /* And'ing with mask[n] masks the lower n bits */
-uInt inflate_mask[17] = {
+uInt cramfs_inflate_mask[17] = {
     0x0000,
     0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
     0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
@@ -20,7 +20,7 @@
 
 
 /* copy as much as possible from the sliding window to the output area */
-int inflate_flush(s, z, r)
+int cramfs_inflate_flush(s, z, r)
 inflate_blocks_statef *s;
 z_streamp z;
 int r;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/infutil.h linux/fs/cramfs/inflate/infutil.h
--- v2.3.99-pre5/linux/fs/cramfs/inflate/infutil.h	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/infutil.h	Wed Apr 12 09:47:29 2000
@@ -67,7 +67,7 @@
 #define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
 #define UPDOUT {s->write=q;}
 #define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+#define LEAVE {UPDATE return cramfs_inflate_flush(s,z,r);}
 /*   get bytes and bits */
 #define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
 #define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
@@ -78,17 +78,17 @@
 #define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
 #define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
 #define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define FLUSH {UPDOUT r=cramfs_inflate_flush(s,z,r); LOADOUT}
 #define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
 #define OUTBYTE(a) {*q++=(Byte)(a);m--;}
 /*   load local pointers */
 #define LOAD {LOADIN LOADOUT}
 
 /* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt inflate_mask[17];
+extern uInt cramfs_inflate_mask[17];
 
 /* copy as much as possible from the sliding window to the output area */
-extern int inflate_flush OF((
+extern int cramfs_inflate_flush OF((
     inflate_blocks_statef *,
     z_streamp ,
     int));
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/uncompr.c linux/fs/cramfs/inflate/uncompr.c
--- v2.3.99-pre5/linux/fs/cramfs/inflate/uncompr.c	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/uncompr.c	Wed Apr 12 09:47:29 2000
@@ -40,16 +40,16 @@
     stream.avail_out = (uInt)*destLen;
     if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
 
-    err = inflateInit(&stream);
+    err = cramfs_inflateInit(&stream);
     if (err != Z_OK) return err;
 
-    err = inflate(&stream, Z_FINISH);
+    err = cramfs_inflate(&stream, Z_FINISH);
     if (err != Z_STREAM_END) {
-        inflateEnd(&stream);
+        cramfs_inflateEnd(&stream);
         return err == Z_OK ? Z_BUF_ERROR : err;
     }
     *destLen = stream.total_out;
 
-    err = inflateEnd(&stream);
+    err = cramfs_inflateEnd(&stream);
     return err;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/inflate/zlib.h linux/fs/cramfs/inflate/zlib.h
--- v2.3.99-pre5/linux/fs/cramfs/inflate/zlib.h	Wed Dec 29 13:13:20 1999
+++ linux/fs/cramfs/inflate/zlib.h	Wed Apr 12 09:47:29 2000
@@ -291,7 +291,7 @@
 
 
 /* 
-ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+ZEXTERN int ZEXPORT cramfs_inflateInit OF((z_streamp strm));
 
      Initializes the internal stream state for decompression. The fields
    next_in, avail_in, zalloc, zfree and opaque must be initialized before by
@@ -311,7 +311,7 @@
 */
 
 
-ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+ZEXTERN int ZEXPORT cramfs_inflate OF((z_streamp strm, int flush));
 /*
     inflate decompresses as much data as possible, and stops when the input
   buffer becomes empty or the output buffer becomes full. It may some
@@ -380,7 +380,7 @@
 */
 
 
-ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+ZEXTERN int ZEXPORT cramfs_inflateEnd OF((z_streamp strm));
 /*
      All dynamically allocated data structures for this stream are freed.
    This function discards any unprocessed input and does not flush any
@@ -569,7 +569,7 @@
    inflate().
 */
 
-ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+ZEXTERN int ZEXPORT cramfs_inflateSync OF((z_streamp strm));
 /* 
     Skips invalid compressed data until a full flush point (see above the
   description of deflate with Z_FULL_FLUSH) can be found, or until all
@@ -584,7 +584,7 @@
   until success or end of the input data.
 */
 
-ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+ZEXTERN int ZEXPORT cramfs_inflateReset OF((z_streamp strm));
 /*
      This function is equivalent to inflateEnd followed by inflateInit,
    but does not free and reallocate all the internal decompression state.
@@ -818,7 +818,7 @@
    compression library.
 */
 
-ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+ZEXTERN uLong ZEXPORT cramfs_adler32 OF((uLong adler, const Bytef *buf, uInt len));
 
 /*
      Update a running Adler-32 checksum with the bytes buf[0..len-1] and
@@ -859,23 +859,23 @@
  */
 ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
                                      const char *version, int stream_size));
-ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ZEXTERN int ZEXPORT cramfs_inflateInit_ OF((z_streamp strm,
                                      const char *version, int stream_size));
 ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
                                       int windowBits, int memLevel,
                                       int strategy, const char *version,
                                       int stream_size));
-ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+ZEXTERN int ZEXPORT cramfs_inflateInit2_ OF((z_streamp strm, int  windowBits,
                                       const char *version, int stream_size));
 #define deflateInit(strm, level) \
         deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define cramfs_inflateInit(strm) \
+        cramfs_inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
 #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
         deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
                       (strategy),           ZLIB_VERSION, sizeof(z_stream))
 #define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+        cramfs_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
 
 
 #if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
@@ -883,7 +883,7 @@
 #endif
 
 ZEXTERN const char   * ZEXPORT zError           OF((int err));
-ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN int            ZEXPORT cramfs_inflateSyncPoint OF((z_streamp z));
 ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
 
 #ifdef __cplusplus
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/cramfs/uncompress.c linux/fs/cramfs/uncompress.c
--- v2.3.99-pre5/linux/fs/cramfs/uncompress.c	Fri Jan 21 18:19:17 2000
+++ linux/fs/cramfs/uncompress.c	Wed Apr 12 09:47:29 2000
@@ -33,14 +33,14 @@
 	stream.next_out = dst;
 	stream.avail_out = dstlen;
 
-	err = inflateReset(&stream);
+	err = cramfs_inflateReset(&stream);
 	if (err != Z_OK) {
-		printk("inflateReset error %d\n", err);
-		inflateEnd(&stream);
-		inflateInit(&stream);
+		printk("cramfs_inflateReset error %d\n", err);
+		cramfs_inflateEnd(&stream);
+		cramfs_inflateInit(&stream);
 	}
 
-	err = inflate(&stream, Z_FINISH);
+	err = cramfs_inflate(&stream, Z_FINISH);
 	if (err != Z_STREAM_END)
 		goto err;
 	return stream.total_out;
@@ -56,7 +56,7 @@
 	if (!initialized++) {
 		stream.next_in = NULL;
 		stream.avail_in = 0;
-		inflateInit(&stream);
+		cramfs_inflateInit(&stream);
 	}
 	return 0;
 }
@@ -64,6 +64,6 @@
 int cramfs_uncompress_exit(void)
 {
 	if (!--initialized)
-		inflateEnd(&stream);
+		cramfs_inflateEnd(&stream);
 	return 0;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/dcache.c linux/fs/dcache.c
--- v2.3.99-pre5/linux/fs/dcache.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/dcache.c	Mon Apr 24 13:59:58 2000
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/cache.h>
 
 #include <asm/uaccess.h>
 
@@ -40,11 +41,12 @@
  * 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     14
-#define D_HASHSIZE     (1UL << D_HASHBITS)
-#define D_HASHMASK     (D_HASHSIZE-1)
+#define D_HASHBITS     d_hash_shift
+#define D_HASHMASK     d_hash_mask
 
-static struct list_head dentry_hashtable[D_HASHSIZE];
+static unsigned int d_hash_mask;
+static unsigned int d_hash_shift;
+static struct list_head *dentry_hashtable;
 static LIST_HEAD(dentry_unused);
 
 struct {
@@ -83,7 +85,7 @@
 }
 
 /* 
- * dput
+ * This is dput
  *
  * This is complicated by the fact that we do not want to put
  * dentries that are no longer on any hash chain on the unused
@@ -534,7 +536,7 @@
  * @parent: parent of entry to allocate
  * @name: qstr of the name
  *
- * Allocates a dentry. It returns NULL if there is insufficient memory
+ * Allocates a dentry. It returns %NULL if there is insufficient memory
  * available. On a success the dentry is returned. The name passed in is
  * copied and the copy passed in may be reused after this call.
  */
@@ -590,7 +592,7 @@
 /**
  * d_instantiate - fill in inode information for a dentry
  * @entry: dentry to complete
- * @inode: inode to attacheto this dentry
+ * @inode: inode to attach to this dentry
  *
  * Fill in inode information in the entry.
  *
@@ -599,7 +601,7 @@
  *
  * NOTE! This assumes that the inode count has been incremented
  * (or otherwise set) by the caller to indicate that it is now
- * in use by the dcache..
+ * in use by the dcache.
  */
  
 void d_instantiate(struct dentry *entry, struct inode * inode)
@@ -613,9 +615,9 @@
  * d_alloc_root - allocate root dentry
  * @root_inode: inode to allocate the root for
  *
- * Allocate a root ('/') dentry for the inode given. The inode is
- * instantiated and returned. NULL is returned if there is insufficient
- * memory or the inode passed is NULL.
+ * Allocate a root ("/") dentry for the inode given. The inode is
+ * instantiated and returned. %NULL is returned if there is insufficient
+ * memory or the inode passed is %NULL.
  */
  
 struct dentry * d_alloc_root(struct inode * root_inode)
@@ -635,7 +637,7 @@
 
 static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
 {
-	hash += (unsigned long) parent;
+	hash += (unsigned long) parent / L1_CACHE_BYTES;
 	hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
 	return dentry_hashtable + (hash & D_HASHMASK);
 }
@@ -648,7 +650,7 @@
  * Searches the children of the parent dentry for the name in question. If
  * the dentry is found its reference count is incremented and the dentry
  * is returned. The caller must use d_put to free the entry when it has
- * finished using it. NULL is returned on failure.
+ * finished using it. %NULL is returned on failure.
  */
  
 struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
@@ -780,7 +782,7 @@
  * d_rehash	- add an entry back to the hash
  * @entry: dentry to add to the hash
  *
- * Adds a dentry to the hash according to its name
+ * Adds a dentry to the hash according to its name.
  */
  
 void d_rehash(struct dentry * entry)
@@ -881,11 +883,11 @@
  * @buffer: buffer to return value in
  * @buflen: buffer length
  *
- * Convert a dentry into an ascii path name. If the entry has been deleted
- * the string ' (deleted)' is appended. Note that this is ambiguous. Returns
+ * Convert a dentry into an ASCII path name. If the entry has been deleted
+ * the string " (deleted)" is appended. Note that this is ambiguous. Returns
  * the buffer.
  *
- * "buflen" should be PAGE_SIZE or more.
+ * "buflen" should be %PAGE_SIZE or more.
  */
 char * __d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
 		struct dentry *root, struct vfsmount *rootmnt,
@@ -1054,10 +1056,12 @@
 	return ino;
 }
 
-void __init dcache_init(void)
+void __init dcache_init(unsigned long mempages)
 {
+	struct list_head *d;
+	unsigned long order;
+	unsigned int nr_hash;
 	int i;
-	struct list_head *d = dentry_hashtable;
 
 	/* 
 	 * A constructor could be added for stable state like the lists,
@@ -1075,7 +1079,34 @@
 	if (!dentry_cache)
 		panic("Cannot create dentry cache");
 
-	i = D_HASHSIZE;
+	mempages >>= (13 - PAGE_SHIFT);
+	mempages *= sizeof(struct list_head);
+	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
+		;
+
+	do {
+		unsigned long tmp;
+
+		nr_hash = (1UL << order) * PAGE_SIZE /
+			sizeof(struct list_head);
+		d_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		d_hash_shift = 0;
+		while ((tmp >>= 1UL) != 0UL)
+			d_hash_shift++;
+
+		dentry_hashtable = (struct list_head *)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while (dentry_hashtable == NULL && --order >= 0);
+
+	if (!dentry_hashtable)
+		panic("Failed to allocate dcache hash table\n");
+
+	printk("VFS: DCACHE hash table configured to %d entries\n", nr_hash);
+
+	d = dentry_hashtable;
+	i = nr_hash;
 	do {
 		INIT_LIST_HEAD(d);
 		d++;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.3.99-pre5/linux/fs/devfs/base.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/devfs/base.c	Fri Apr 21 16:11:05 2000
@@ -432,6 +432,17 @@
 	       <devfs_readdir>.
 	       Work sponsored by SGI.
   v0.93
+    20000413   Richard Gooch <rgooch@atnf.csiro.au>
+	       Set inode->i_size to correct size for symlinks.
+    20000414   Richard Gooch <rgooch@atnf.csiro.au>
+	       Only give lookup() method to directories to comply with new VFS
+	       assumptions.
+	       Work sponsored by SGI.
+    20000415   Richard Gooch <rgooch@atnf.csiro.au>
+	       Remove unnecessary tests in symlink methods.
+	       Don't kill existing block ops in <devfs_read_inode>.
+	       Work sponsored by SGI.
+  v0.94
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -466,7 +477,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "0.93 (20000306)"
+#define DEVFS_VERSION            "0.94 (20000415)"
 
 #ifndef DEVFS_NAME
 #  define DEVFS_NAME "devfs"
@@ -679,7 +690,9 @@
 static unsigned int devfs_debug = DEBUG_NONE;
 #  endif
 #endif
-static unsigned int boot_options = OPTION_NONE;
+
+/* by default, we do not mount devfs on bootup */
+static unsigned int boot_options = OPTION_NOMOUNT;
 
 /*  Forward function declarations  */
 static struct devfs_entry *search_for_entry (struct devfs_entry *dir,
@@ -1916,6 +1929,11 @@
 	    boot_options |= OPTION_ONLY;
 	    str += 4;
 	}
+	else if (strncmp (str, "mount", 5) == 0)
+	{
+	    boot_options &= ~OPTION_NOMOUNT;
+	    str += 5;
+	}
 	else if (strncmp (str, "nomount", 7) == 0)
 	{
 	    boot_options |= OPTION_NOMOUNT;
@@ -2185,6 +2203,7 @@
 /*  Superblock operations follow  */
 
 static struct inode_operations devfs_iops;
+static struct inode_operations devfs_dir_iops;
 static struct file_operations devfs_fops;
 static struct inode_operations devfs_symlink_iops;
 
@@ -2208,28 +2227,33 @@
     inode->i_blocks = 0;
     inode->i_blksize = 1024;
     inode->i_op = &devfs_iops;
+    inode->i_fop = &devfs_fops;
     inode->i_rdev = NODEV;
-    if ( S_ISCHR (di->mode) ) {
+    if ( S_ISCHR (di->mode) )
+    {
 	inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major,
 			       di->de->u.fcb.u.device.minor);
-	inode->i_fop = &devfs_fops;
-    } else if ( S_ISBLK (di->mode) ) {
+    }
+    else if ( S_ISBLK (di->mode) )
+    {
 	inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major,
 			       di->de->u.fcb.u.device.minor);
 	inode->i_bdev = bdget (inode->i_rdev);
-	if (inode->i_bdev) inode->i_bdev->bd_op = di->de->u.fcb.ops;
+	if (inode->i_bdev)
+	{
+	    if (!inode->i_bdev->bd_op && di->de->u.fcb.ops)
+		inode->i_bdev->bd_op = di->de->u.fcb.ops;
+	}
 	else printk ("%s: read_inode(%d): no block device from bdget()\n",
 		     DEVFS_NAME, (int) inode->i_ino);
-	inode->i_fop = &devfs_fops;
-    } else if ( S_ISFIFO (di->mode) ) {
-	inode->i_fop = &def_fifo_fops;
-    } else if ( S_ISREG (di->mode) ) {
-	inode->i_size = di->de->u.fcb.u.file.size;
-	inode->i_fop = &devfs_fops;
-    } else if (S_ISLNK(di->mode)) {
+    }
+    else if ( S_ISFIFO (di->mode) ) inode->i_fop = &def_fifo_fops;
+    else if ( S_ISREG (di->mode) ) inode->i_size = di->de->u.fcb.u.file.size;
+    else if ( S_ISDIR (di->mode) ) inode->i_op = &devfs_dir_iops;
+    else if ( S_ISLNK (di->mode) )
+    {
 	inode->i_op = &devfs_symlink_iops;
-    } else {
-	inode->i_fop = &devfs_fops;
+	inode->i_size = di->de->u.symlink.length;
     }
     inode->i_mode = di->mode;
     inode->i_uid = di->uid;
@@ -2358,7 +2382,7 @@
 
 /*  File operations for device entries follow  */
 
-static int devfs_read (struct file *file, char *buf, size_t len, loff_t *ppos)
+static ssize_t devfs_read (struct file *file, char *buf, size_t len, loff_t *ppos)
 {
     if ( S_ISDIR (file->f_dentry->d_inode->i_mode) ) return -EISDIR;
     return -EINVAL;
@@ -2747,7 +2771,7 @@
 	    de = search_for_entry_in_dir (parent, dentry->d_name.name,
 					  dentry->d_name.len, FALSE);
     }
-    if ( (de == NULL) || (!de->registered) )
+    if ( (de == NULL) || !de->registered )
     {
 	/*  Try with devfsd. For any kind of failure, leave a negative dentry
 	    so someone else can deal with it (in the case where the sysadmin
@@ -3083,41 +3107,46 @@
 
 static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen)
 {
-	struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode);
-	char *name = ERR_PTR(-ENOENT);
+    struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode);
 
-	if (di && di->de->registered)
-		name = di->de->u.symlink.linkname;
-	return vfs_readlink(dentry, buffer, buflen, name);
+    return vfs_readlink (dentry, buffer, buflen, di->de->u.symlink.linkname);
 }   /*  End Function devfs_readlink  */
 
 static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd)
 {
-	struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode);
-	char *name = ERR_PTR(-ENOENT);
+    struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode);
 
-	if (di && di->de->registered)
-		name = di->de->u.symlink.linkname;
-	return vfs_follow_link(nd, name);
+    return vfs_follow_link (nd, di->de->u.symlink.linkname);
 }   /*  End Function devfs_follow_link  */
 
 static struct inode_operations devfs_iops =
 {
-	lookup:		devfs_lookup,
-	link:		devfs_link,
-	unlink:		devfs_unlink,
-	symlink:	devfs_symlink,
-	mkdir:		devfs_mkdir,
-	rmdir:		devfs_rmdir,
-	mknod:		devfs_mknod,
-	setattr:	devfs_notify_change,
+    link:           devfs_link,
+    unlink:         devfs_unlink,
+    symlink:        devfs_symlink,
+    mkdir:          devfs_mkdir,
+    rmdir:          devfs_rmdir,
+    mknod:          devfs_mknod,
+    setattr:        devfs_notify_change,
+};
+
+static struct inode_operations devfs_dir_iops =
+{
+    lookup:         devfs_lookup,
+    link:           devfs_link,
+    unlink:         devfs_unlink,
+    symlink:        devfs_symlink,
+    mkdir:          devfs_mkdir,
+    rmdir:          devfs_rmdir,
+    mknod:          devfs_mknod,
+    setattr:        devfs_notify_change,
 };
 
 static struct inode_operations devfs_symlink_iops =
 {
-	readlink:	devfs_readlink,
-	follow_link:	devfs_follow_link,
-	setattr:	devfs_notify_change,
+    readlink:       devfs_readlink,
+    follow_link:    devfs_follow_link,
+    setattr:        devfs_notify_change,
 };
 
 static struct super_block *devfs_read_super (struct super_block *sb,
@@ -3179,7 +3208,7 @@
 }   /*  End Function devfs_read_super  */
 
 
-static DECLARE_FSTYPE(devfs_fs_type, DEVFS_NAME, devfs_read_super, 0);
+static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, 0);
 
 
 /*  File operations for devfsd follow  */
@@ -3308,7 +3337,7 @@
 	    doesn't matter who gets in first, as long as only one gets it  */
 	if (fs_info->devfsd_task == NULL)
 	{
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	    /*  Looks like no-one has it: check again and grab, with interrupts
 		disabled  */
 	    __cli ();
@@ -3318,7 +3347,7 @@
 		fs_info->devfsd_event_mask = 0;  /*  Temporary disable  */
 		fs_info->devfsd_task = current;
 	    }
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	    __sti ();
 #endif
 	}
@@ -3392,7 +3421,7 @@
 {
     int err;
     extern long do_sys_mount (char *dev_name, char *dir_name,
-				char * type, int flags, void * data);
+			      char *type, int flags, void *data);
 
     if ( (boot_options & OPTION_NOMOUNT) ) return;
     err = do_sys_mount ("none", "/dev", "devfs", 0, "");
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/efs/inode.c linux/fs/efs/inode.c
--- v2.3.99-pre5/linux/fs/efs/inode.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/efs/inode.c	Tue Apr 25 17:28:55 2000
@@ -21,6 +21,7 @@
 }
 struct address_space_operations efs_aops = {
 	readpage: efs_readpage,
+	sync_page: block_sync_page,
 	bmap: _efs_bmap
 };
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/exec.c linux/fs/exec.c
--- v2.3.99-pre5/linux/fs/exec.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/exec.c	Fri Apr 21 13:36:39 2000
@@ -315,30 +315,30 @@
 	return 0;
 }
 
-/* MOUNT_REWRITE: &mnt should be passed to lookup_dentry */
 struct file *open_exec(const char *name)
 {
-	struct dentry *dentry;
-	struct vfsmount *mnt = NULL;
+	struct nameidata nd;
 	struct file *file;
+	int err = 0;
 
 	lock_kernel();
-	dentry = lookup_dentry(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-	file = (struct file*) dentry;
-	if (!IS_ERR(dentry)) {
+	if (walk_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
+		err = walk_name(name, &nd);
+	file = ERR_PTR(err);
+	if (!err) {
 		file = ERR_PTR(-EACCES);
-		if (S_ISREG(dentry->d_inode->i_mode)) {
-			int err = permission(dentry->d_inode, MAY_EXEC);
+		if (S_ISREG(nd.dentry->d_inode->i_mode)) {
+			int err = permission(nd.dentry->d_inode, MAY_EXEC);
 			file = ERR_PTR(err);
 			if (!err) {
-				file = dentry_open(dentry, mnt, O_RDONLY);
+				file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
 out:
 				unlock_kernel();
 				return file;
 			}
 		}
-		dput(dentry);
-		mntput(mnt);
+		dput(nd.dentry);
+		mntput(nd.mnt);
 	}
 	goto out;
 }
@@ -856,6 +856,16 @@
 			__free_page(bprm.page[i]);
 
 	return retval;
+}
+
+void set_binfmt(struct linux_binfmt *new)
+{
+	struct linux_binfmt *old = current->binfmt;
+	if (new && new->module)
+		__MOD_INC_USE_COUNT(new->module);
+	current->binfmt = new;
+	if (old && old->module)
+		__MOD_DEC_USE_COUNT(old->module);
 }
 
 int do_coredump(long signr, struct pt_regs * regs)
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.3.99-pre5/linux/fs/ext2/inode.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/ext2/inode.c	Tue Apr 25 17:28:56 2000
@@ -620,7 +620,7 @@
 	return NULL;
 }
 
-static int ext2_writepage(struct dentry *dentry, struct page *page)
+static int ext2_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,ext2_get_block);
 }
@@ -639,6 +639,7 @@
 struct address_space_operations ext2_aops = {
 	readpage: ext2_readpage,
 	writepage: ext2_writepage,
+	sync_page: block_sync_page,
 	prepare_write: ext2_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: ext2_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.3.99-pre5/linux/fs/ext2/namei.c	Tue Apr 11 15:09:21 2000
+++ linux/fs/ext2/namei.c	Mon Apr 24 18:56:32 2000
@@ -218,19 +218,10 @@
 	struct super_block * sb;
 	int	retval;
 
-	if (!dir || !dir->i_nlink)
-		return -EINVAL;
 	sb = dir->i_sb;
 
 	if (!namelen)
 		return -EINVAL;
-	/*
-	 * Is this a busy deleted directory?  Can't create new files if so
-	 */
-	if (dir->i_size == 0)
-	{
-		return -ENOENT;
-	}
 	bh = ext2_bread (dir, 0, 0, &retval);
 	if (!bh)
 		return retval;
@@ -284,13 +275,13 @@
 				de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
 				de = de1;
 			}
+			de->file_type = EXT2_FT_UNKNOWN;
 			if (inode) {
 				de->inode = cpu_to_le32(inode->i_ino);
 				ext2_set_de_type(dir->i_sb, de, inode->i_mode);
 			} else
 				de->inode = 0;
 			de->name_len = namelen;
-			de->file_type = 0;
 			memcpy (de->name, name, namelen);
 			/*
 			 * XXX shouldn't update any times until successful
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.3.99-pre5/linux/fs/fat/file.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/fat/file.c	Wed Apr 12 09:47:29 2000
@@ -125,7 +125,13 @@
 	if (IS_IMMUTABLE(inode))
 		return /* -EPERM */;
 	cluster = SECTOR_SIZE*sbi->cluster_size;
-	MSDOS_I(inode)->mmu_private = inode->i_size;
+	/* 
+	 * This protects against truncating a file bigger than it was then
+	 * trying to write into the hole.
+	 */
+	if (MSDOS_I(inode)->mmu_private > inode->i_size)
+		MSDOS_I(inode)->mmu_private = inode->i_size;
+
 	fat_free(inode,(inode->i_size+(cluster-1))>>sbi->cluster_bits);
 	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.3.99-pre5/linux/fs/fat/inode.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/fat/inode.c	Tue Apr 25 17:28:56 2000
@@ -729,7 +729,7 @@
 	return 0;
 }
 
-static int fat_writepage(struct dentry *dentry, struct page *page)
+static int fat_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,fat_get_block);
 }
@@ -749,6 +749,7 @@
 static struct address_space_operations fat_aops = {
 	readpage: fat_readpage,
 	writepage: fat_writepage,
+	sync_page: block_sync_page,
 	prepare_write: fat_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: _fat_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/hfs/inode.c linux/fs/hfs/inode.c
--- v2.3.99-pre5/linux/fs/hfs/inode.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/hfs/inode.c	Tue Apr 25 17:28:56 2000
@@ -217,7 +217,7 @@
 	return __hfs_notify_change(dentry, attr, HFS_HDR);
 }
 
-static int hfs_writepage(struct dentry *dentry, struct page *page)
+static int hfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,hfs_get_block);
 }
@@ -237,6 +237,7 @@
 struct address_space_operations hfs_aops = {
 	readpage: hfs_readpage,
 	writepage: hfs_writepage,
+	sync_page: block_sync_page,
 	prepare_write: hfs_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: hfs_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.3.99-pre5/linux/fs/hpfs/file.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/hpfs/file.c	Tue Apr 25 17:28:56 2000
@@ -86,7 +86,7 @@
 	return 0;
 }
 
-static int hpfs_writepage(struct dentry *dentry, struct page *page)
+static int hpfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,hpfs_get_block);
 }
@@ -106,6 +106,7 @@
 struct address_space_operations hpfs_aops = {
 	readpage: hpfs_readpage,
 	writepage: hpfs_writepage,
+	sync_page: block_sync_page,
 	prepare_write: hpfs_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: _hpfs_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/hpfs/namei.c linux/fs/hpfs/namei.c
--- v2.3.99-pre5/linux/fs/hpfs/namei.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/hpfs/namei.c	Mon Apr 24 18:56:32 2000
@@ -375,11 +375,6 @@
 		hpfs_unlock_2inodes(dir, inode);
 		return -ENOTDIR;
 	}
-	if (!d_unhashed(dentry)) {
-		hpfs_brelse4(&qbh);
-		hpfs_unlock_2inodes(dir, inode);
-		return -EBUSY;
-	}
 	hpfs_count_dnodes(dir->i_sb, inode->i_hpfs_dno, NULL, NULL, &n_items);
 	if (n_items) {
 		hpfs_brelse4(&qbh);
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/inode.c linux/fs/inode.c
--- v2.3.99-pre5/linux/fs/inode.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/inode.c	Mon Apr 24 13:59:58 2000
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/quotaops.h>
 #include <linux/slab.h>
+#include <linux/cache.h>
 
 /*
  * New inode.c implementation.
@@ -32,9 +33,11 @@
  * 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	14
-#define HASH_SIZE	(1UL << HASH_BITS)
-#define HASH_MASK	(HASH_SIZE-1)
+#define I_HASHBITS	i_hash_shift
+#define I_HASHMASK	i_hash_mask
+
+static unsigned int i_hash_mask;
+static unsigned int i_hash_shift;
 
 /*
  * Each inode can be on two separate lists. One is
@@ -50,7 +53,7 @@
 
 static LIST_HEAD(inode_in_use);
 static LIST_HEAD(inode_unused);
-static struct list_head inode_hashtable[HASH_SIZE];
+static struct list_head *inode_hashtable;
 static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */
 
 /*
@@ -116,7 +119,7 @@
  *	__mark_inode_dirty -	internal function
  *	@inode: inode to mark
  *
- *	Mark an inode as dirty. Callers should use mark_inode_dirty
+ *	Mark an inode as dirty. Callers should use mark_inode_dirty.
  */
  
 void __mark_inode_dirty(struct inode *inode)
@@ -530,7 +533,7 @@
  * no pre-existing information.
  *
  * On a successful return the inode pointer is returned. On a failure
- * a NULL pointer is returned. The returned inode is not on any superblock
+ * a %NULL pointer is returned. The returned inode is not on any superblock
  * lists.
  */
  
@@ -617,9 +620,9 @@
 
 static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
 {
-	unsigned long tmp = i_ino | (unsigned long) sb;
-	tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
-	return tmp & HASH_MASK;
+	unsigned long tmp = i_ino | ((unsigned long) sb / L1_CACHE_BYTES);
+	tmp = tmp + (tmp >> I_HASHBITS) + (tmp >> I_HASHBITS*2);
+	return tmp & I_HASHMASK;
 }
 
 /* Yeah, I know about quadratic hash. Maybe, later. */
@@ -707,7 +710,7 @@
  *	@inode: unhashed inode
  *
  *	Add an inode to the inode hash for this superblock. If the inode
- *	has no superblock it is added to a seperate anonymous chain
+ *	has no superblock it is added to a separate anonymous chain.
  */
  
 void insert_inode_hash(struct inode *inode)
@@ -724,7 +727,7 @@
  *	remove_inode_hash - remove an inode from the hash
  *	@inode: inode to unhash
  *
- *	Remove an inode from the superblock or anonymous hash
+ *	Remove an inode from the superblock or anonymous hash.
  */
  
 void remove_inode_hash(struct inode *inode)
@@ -829,9 +832,9 @@
  *
  *	Returns the block number on the device holding the inode that
  *	is the disk block number for the block of the file requested.
- *	That is asked for block 4 of inode 1 the function will return the
+ *	That is, asked for block 4 of inode 1 the function will return the
  *	disk block relative to the disk start that holds that block of the 
- *	file
+ *	file.
  */
  
 int bmap(struct inode * inode, int block)
@@ -845,12 +848,41 @@
 /*
  * Initialize the hash tables.
  */
-void __init inode_init(void)
+void __init inode_init(unsigned long mempages)
 {
+	struct list_head *head;
+	unsigned long order;
+	unsigned int nr_hash;
 	int i;
-	struct list_head *head = inode_hashtable;
 
-	i = HASH_SIZE;
+	mempages >>= (14 - PAGE_SHIFT);
+	mempages *= sizeof(struct list_head);
+	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
+		;
+
+	do {
+		unsigned long tmp;
+
+		nr_hash = (1UL << order) * PAGE_SIZE /
+			sizeof(struct list_head);
+		i_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		i_hash_shift = 0;
+		while ((tmp >>= 1UL) != 0UL)
+			i_hash_shift++;
+
+		inode_hashtable = (struct list_head *)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while (inode_hashtable == NULL && --order >= 0);
+
+	if (!inode_hashtable)
+		panic("Failed to allocate inode hash table\n");
+
+	printk("VFS: INODE hash table configured to %d entries\n", nr_hash);
+
+	head = inode_hashtable;
+	i = nr_hash;
 	do {
 		INIT_LIST_HEAD(head);
 		head++;
@@ -869,9 +901,9 @@
  *	update_atime	-	update the access time
  *	@inode: inode accessed
  *
- *	Update the accessed time on an inode and mark it for  writeback.
+ *	Update the accessed time on an inode and mark it for writeback.
  *	This function automatically handles read only file systems and media,
- *	as well as the noatime flag and inode specific noatime markers
+ *	as well as the "noatime" flag and inode specific "noatime" markers.
  */
  
 void update_atime (struct inode *inode)
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.99-pre5/linux/fs/isofs/inode.c	Tue Mar 14 19:10:40 2000
+++ linux/fs/isofs/inode.c	Tue Apr 25 17:28:55 2000
@@ -991,6 +991,7 @@
 }
 static struct address_space_operations isofs_aops = {
 	readpage: isofs_readpage,
+	sync_page: block_sync_page,
 	bmap: _isofs_bmap
 };
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/locks.c linux/fs/locks.c
--- v2.3.99-pre5/linux/fs/locks.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/locks.c	Fri Apr 21 15:42:34 2000
@@ -130,7 +130,7 @@
 					 struct file_lock *);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
 static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait);
-static char *lock_get_status(struct file_lock *fl, int id, char *pfx);
+static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx);
 
 static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter);
 static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter);
@@ -1179,90 +1179,85 @@
 	return;
 }
 
-
-static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
+static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
 {
-	static char temp[155];
-	char *p = temp;
 	struct inode *inode;
 
 	inode = fl->fl_file->f_dentry->d_inode;
 
-	p += sprintf(p, "%d:%s ", id, pfx);
+	out += sprintf(out, "%d:%s ", id, pfx);
 	if (fl->fl_flags & FL_POSIX) {
-		p += sprintf(p, "%6s %s ",
+		out += sprintf(out, "%6s %s ",
 			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
 			     (IS_MANDLOCK(inode) &&
 			      (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
 			     "MANDATORY" : "ADVISORY ");
 	}
 	else {
-		p += sprintf(p, "FLOCK  ADVISORY  ");
+		out += sprintf(out, "FLOCK  ADVISORY  ");
 	}
-	p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
-	p += sprintf(p, "%d %s:%ld %Ld %Ld ",
+	out += sprintf(out, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
+	out += sprintf(out, "%d %s:%ld %Ld %Ld ",
 		     fl->fl_pid,
 		     kdevname(inode->i_dev), inode->i_ino,
 		     (long long)fl->fl_start, (long long)fl->fl_end);
-	sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
+	sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n",
 		(long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
 		(long)fl->fl_next, (long)fl->fl_nextblock);
-	return (temp);
 }
 
-static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
-				   off_t offset, int length)
+static void move_lock_status(char **p, off_t* pos, off_t offset)
 {
-	off_t i;
-
-	i = pos - offset;
-	if (i > 0) {
-		if (i >= length) {
-			i = len + length - i;
-			memcpy(*q, p, i);
-			*q += i;
-			return (0);
-		}
-		if (i < len) {
-			p += len - i;
-		}
-		else
-			i = len;
-		memcpy(*q, p, i);
-		*q += i;
+	int len;
+	len = strlen(*p);
+	if(*pos >= offset) {
+		/* the complete line is valid */
+		*p += len;
+		*pos += len;
+		return;
 	}
-	
-	return (1);
+	if(*pos+len > offset) {
+		/* use the second part of the line */
+		int i = offset-*pos;
+		memmove(*p,*p+i,len-i);
+		*p += len-i;
+		*pos += len;
+		return;
+	}
+	/* discard the complete line */
+	*pos += len;
 }
 
 int get_locks_status(char *buffer, char **start, off_t offset, int length)
 {
 	struct file_lock *fl;
 	struct file_lock *bfl;
-	char *p;
 	char *q = buffer;
-	off_t i, len, pos = 0;
+	off_t pos = 0;
+	int i;
 
 	for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
-		p = lock_get_status(fl, i, "");
-		len = strlen(p);
-		pos += len;
-		if (!copy_lock_status(p, &q, pos, len, offset, length))
+		lock_get_status(q, fl, i, "");
+		move_lock_status(&q, &pos, offset);
+
+		if(pos >= offset+length)
 			goto done;
+
 		if ((bfl = fl->fl_nextblock) == NULL)
 			continue;
 		do {
-			p = lock_get_status(bfl, i, " ->");
-			len = strlen(p);
-			pos += len;
-			if (!copy_lock_status(p, &q, pos, len, offset, length))
+			lock_get_status(q, bfl, i, " ->");
+			move_lock_status(&q, &pos, offset);
+
+			if(pos >= offset+length)
 				goto done;
 		} while ((bfl = bfl->fl_nextblock) != fl);
 	}
 done:
-	if (q != buffer)
-		*start = buffer;
-	return (q - buffer);
+	*start = buffer;
+	if(q-buffer < length)
+		return (q-buffer);
+	return length;
 }
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.3.99-pre5/linux/fs/minix/inode.c	Mon Mar 27 08:08:29 2000
+++ linux/fs/minix/inode.c	Tue Apr 25 17:28:56 2000
@@ -1006,7 +1006,7 @@
 	return NULL;
 }
 
-static int minix_writepage(struct dentry *dentry, struct page *page)
+static int minix_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,minix_get_block);
 }
@@ -1025,6 +1025,7 @@
 struct address_space_operations minix_aops = {
 	readpage: minix_readpage,
 	writepage: minix_writepage,
+	sync_page: block_sync_page,
 	prepare_write: minix_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: minix_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.3.99-pre5/linux/fs/minix/namei.c	Fri Mar 10 16:40:47 2000
+++ linux/fs/minix/namei.c	Mon Apr 24 18:56:33 2000
@@ -399,10 +399,6 @@
 		retval = -ENOENT;
 		goto end_rmdir;
 	}
-	if (!d_unhashed(dentry)) {
-		retval = -EBUSY;
-		goto end_rmdir;
-	}
 	if (inode->i_nlink != 2)
 		printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
 	de->inode = 0;
@@ -569,9 +565,6 @@
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
 		if (new_inode) {
-			retval = -EBUSY;
-			if (!d_unhashed(new_dentry))
-				goto end_rename;
 			retval = -ENOTEMPTY;
 			if (!empty_dir(new_inode))
 				goto end_rename;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.3.99-pre5/linux/fs/msdos/namei.c	Tue Mar 14 19:10:40 2000
+++ linux/fs/msdos/namei.c	Mon Apr 24 18:56:33 2000
@@ -325,9 +325,6 @@
 	 * Check whether the directory is not in use, then check
 	 * whether it is empty.
 	 */
-	res = -EBUSY;
-	if (!d_unhashed(dentry))
-		goto rmdir_done;
 	res = fat_dir_empty(inode);
 	if (res)
 		goto rmdir_done;
@@ -463,9 +460,6 @@
 		goto degenerate_case;
 	if (is_dir) {
 		if (new_inode) {
-			error = -EBUSY;
-			if (!d_unhashed(new_dentry))
-				goto out;
 			error = fat_dir_empty(new_inode);
 			if (error)
 				goto out;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/namei.c linux/fs/namei.c
--- v2.3.99-pre5/linux/fs/namei.c	Wed Apr 12 10:02:34 2000
+++ linux/fs/namei.c	Mon Apr 24 18:56:33 2000
@@ -286,11 +286,12 @@
  *
  * We expect 'base' to be positive and a directory.
  */
-int walk_name(const char * name, unsigned lookup_flags, struct nameidata *nd)
+int walk_name(const char * name, struct nameidata *nd)
 {
 	struct dentry *dentry;
 	struct inode *inode;
 	int err;
+	unsigned int lookup_flags = nd->flags;
 
 	while (*name=='/')
 		name++;
@@ -301,9 +302,6 @@
 	if (current->link_count)
 		lookup_flags = LOOKUP_FOLLOW;
 
-	lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY |
-			LOOKUP_SLASHOK | LOOKUP_POSITIVE | LOOKUP_PARENT;
-
 	/* At this point we know we have a real path component. */
 	for(;;) {
 		unsigned long hash;
@@ -379,10 +377,10 @@
 		err = -ENOENT;
 		inode = dentry->d_inode;
 		if (!inode)
-			break;
+			goto out_dput;
 		err = -ENOTDIR; 
 		if (!inode->i_op)
-			break;
+			goto out_dput;
 
 		if (inode->i_op->follow_link) {
 			err = do_follow_link(dentry, nd);
@@ -464,16 +462,23 @@
 		goto return_base;
 no_inode:
 		err = -ENOENT;
-		if (lookup_flags & LOOKUP_POSITIVE)
+		if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))
 			break;
-		if (lookup_flags & LOOKUP_DIRECTORY)
-			if (!(lookup_flags & LOOKUP_SLASHOK))
-				break;
 		goto return_base;
 lookup_parent:
 		nd->last = this;
+		nd->last_type = LAST_NORM;
+		if (this.name[0] != '.')
+			goto return_base;
+		if (this.len == 1)
+			nd->last_type = LAST_DOT;
+		else if (this.len == 2 && this.name[1] == '.')
+			nd->last_type = LAST_DOTDOT;
 return_base:
 		return 0;
+out_dput:
+		dput(dentry);
+		break;
 	}
 	dput(nd->dentry);
 	mntput(nd->mnt);
@@ -482,27 +487,20 @@
 }
 
 /* returns 1 if everything is done */
-static int __emul_lookup_dentry(const char *name, int lookup_flags,
-		struct nameidata *nd)
+static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
 {
-	char *emul = __emul_prefix();
-
-	if (!emul)
-		return 0;
-
-	nd->mnt = mntget(current->fs->rootmnt);
-	nd->dentry = dget(current->fs->root);
-	if (walk_name(emul,LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE,nd))
-		return 0;
-	if (walk_name(name, lookup_flags, nd))
+	nd->mnt = mntget(current->fs->altrootmnt);
+	nd->dentry = dget(current->fs->altroot);
+	if (walk_name(name, nd))
 		return 0;
 
 	if (!nd->dentry->d_inode) {
 		struct nameidata nd_root;
-		nd_root.last.len = 0;
+		nd_root.last_type = LAST_ROOT;
+		nd_root.flags = nd->flags;
 		nd_root.mnt = mntget(current->fs->rootmnt);
 		nd_root.dentry = dget(current->fs->root);
-		if (walk_name(name, lookup_flags, &nd_root))
+		if (walk_name(name, &nd_root))
 			return 1;
 		if (nd_root.dentry->d_inode) {
 			dput(nd->dentry);
@@ -518,11 +516,36 @@
 	return 1;
 }
 
+void set_fs_altroot(void)
+{
+	char *emul = __emul_prefix();
+	struct nameidata nd;
+	struct vfsmount *mnt = NULL, *oldmnt;
+	struct dentry *dentry = NULL, *olddentry;
+	if (emul) {
+		nd.mnt = mntget(current->fs->rootmnt);
+		nd.dentry = dget(current->fs->root);
+		nd.flags = LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE;
+		if (walk_name(emul,&nd) == 0) {
+			mnt = nd.mnt;
+			dentry = nd.dentry;
+		}
+	}
+	oldmnt = current->fs->altrootmnt;
+	olddentry = current->fs->altroot;
+	current->fs->altrootmnt = mnt;
+	current->fs->altroot = dentry;
+	if (olddentry) {
+		dput(olddentry);
+		mntput(oldmnt);
+	}
+}
+
 static inline int
-walk_init_root(const char *name, unsigned flags, struct nameidata *nd)
+walk_init_root(const char *name, struct nameidata *nd)
 {
-	if (current->personality != PER_LINUX)
-		if (__emul_lookup_dentry(name,flags,nd))
+	if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT))
+		if (__emul_lookup_dentry(name,nd))
 			return 0;
 	nd->mnt = mntget(current->fs->rootmnt);
 	nd->dentry = dget(current->fs->root);
@@ -531,9 +554,10 @@
 
 int walk_init(const char *name,unsigned int flags,struct nameidata *nd)
 {
-	nd->last.len = 0;
+	nd->last_type = LAST_ROOT; /* if there are only slashes... */
+	nd->flags = flags;
 	if (*name=='/')
-		return walk_init_root(name,flags,nd);
+		return walk_init_root(name,nd);
 	nd->mnt = mntget(current->fs->pwdmnt);
 	nd->dentry = dget(current->fs->pwd);
 	return 1;
@@ -545,7 +569,7 @@
 	int err = 0;
 
 	if (walk_init(name, lookup_flags, &nd))
-		err = walk_name(name, lookup_flags, &nd);
+		err = walk_name(name, &nd);
 	if (!err) {
 		mntput(nd.mnt);
 		return nd.dentry;
@@ -589,15 +613,10 @@
 		dentry = inode->i_op->lookup(inode, new);
 		if (!dentry)
 			dentry = new;
-		else {
+		else
 			dput(new);
-			if (IS_ERR(dentry))
-				goto out;
-		}
 	}
-
 out:
-	dput(base);
 	return dentry;
 }
 
@@ -689,6 +708,8 @@
 	int error;
 	if (!victim->d_inode || victim->d_parent->d_inode != dir)
 		return -ENOENT;
+	if (IS_DEADDIR(dir))
+		return -ENOENT;
 	error = permission(dir,MAY_WRITE | MAY_EXEC);
 	if (error)
 		return error;
@@ -720,6 +741,8 @@
 static inline int may_create(struct inode *dir, struct dentry *child) {
 	if (child->d_inode)
 		return -EEXIST;
+	if (IS_DEADDIR(dir))
+		return -ENOENT;
 	return permission(dir,MAY_WRITE | MAY_EXEC);
 }
 
@@ -790,7 +813,7 @@
 	acc_mode = ACC_MODE(flag);
 	if (!(flag & O_CREAT)) {
 		if (walk_init(pathname, lookup_flags(flag), nd))
-			error = walk_name(pathname, lookup_flags(flag), nd);
+			error = walk_name(pathname, nd);
 		if (error)
 			return error;
 
@@ -799,7 +822,7 @@
 		struct dentry *dir;
 
 		if (walk_init(pathname, LOOKUP_PARENT, nd))
-			error = walk_name(pathname, LOOKUP_PARENT, nd);
+			error = walk_name(pathname, nd);
 		if (error)
 			return error;
 		/*
@@ -810,9 +833,7 @@
 		 * luserdom and let him sod off - -EISDIR it is.
 		 */
 		error = -EISDIR;
-		if (!nd->last.len || (nd->last.name[0] == '.' &&
-		     (nd->last.len == 1 ||
-		      (nd->last.name[1] == '.' && nd->last.len == 2))))
+		if (nd->last_type != LAST_NORM)
 			goto exit;
 		/* same for foo/ */
 		if (nd->last.name[nd->last.len])
@@ -821,7 +842,7 @@
 		dir = dget(nd->dentry);
 		down(&dir->d_inode->i_sem);
 
-		dentry = lookup_hash(&nd->last, dget(nd->dentry));
+		dentry = lookup_hash(&nd->last, nd->dentry);
 		error = PTR_ERR(dentry);
 		if (IS_ERR(dentry)) {
 			up(&dir->d_inode->i_sem);
@@ -834,7 +855,7 @@
 			dput(dir);
 			error = -EEXIST;
 			if (flag & O_EXCL)
-				goto exit;
+				goto exit_dput;
 			if (dentry->d_inode->i_op &&
 			    dentry->d_inode->i_op->follow_link) {
 				/*
@@ -936,6 +957,8 @@
 
 	return 0;
 
+exit_dput:
+	dput(dentry);
 exit:
 	dput(nd->dentry);
 	mntput(nd->mnt);
@@ -948,16 +971,15 @@
 	struct dentry *dentry;
 	int err = 0;
 	if (walk_init(name, LOOKUP_PARENT, &nd))
-		err = walk_name(name, LOOKUP_PARENT, &nd);
+		err = walk_name(name, &nd);
 	dentry = ERR_PTR(err);
 	if (err)
 		goto out;
 	down(&nd.dentry->d_inode->i_sem);
 	dentry = ERR_PTR(-EEXIST);
-	if (!nd.last.len || (nd.last.name[0] == '.' &&
-	      (nd.last.len == 1 || (nd.last.name[1] == '.' && nd.last.len == 2))))
+	if (nd.last_type != LAST_NORM)
 		goto fail;
-	dentry = lookup_hash(&nd.last, dget(nd.dentry));
+	dentry = lookup_hash(&nd.last, nd.dentry);
 	if (IS_ERR(dentry))
 		goto fail;
 	if (!is_dir && nd.last.name[nd.last.len] && !dentry->d_inode)
@@ -1155,47 +1177,53 @@
 	double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
 	d_unhash(dentry);
 	error = dir->i_op->rmdir(dir, dentry);
+	if (!error)
+		dentry->d_inode->i_flags |= S_DEAD;
 	double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
 	dput(dentry);
 
 	return error;
 }
 
-static inline int do_rmdir(const char * name)
+asmlinkage long sys_rmdir(const char * pathname)
 {
-	int error;
-	struct dentry *dir;
+	int error = 0;
+	char * name;
 	struct dentry *dentry;
+	struct nameidata nd;
 
-	dentry = lookup_dentry(name, LOOKUP_POSITIVE);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	name = getname(pathname);
+	if(IS_ERR(name))
+		return PTR_ERR(name);
+	lock_kernel();
+
+	if (walk_init(name, LOOKUP_PARENT, &nd))
+		error = walk_name(name, &nd);
+	if (error)
 		goto exit;
 
-	dir = lock_parent(dentry);
-	error = -ENOENT;
-	if (check_parent(dir, dentry))
-		error = vfs_rmdir(dir->d_inode, dentry);
-	unlock_dir(dir);
-	dput(dentry);
+	switch(nd.last_type) {
+		case LAST_DOTDOT:
+			error = -ENOTEMPTY;
+			goto exit1;
+		case LAST_ROOT: case LAST_DOT:
+			error = -EBUSY;
+			goto exit1;
+	}
+	down(&nd.dentry->d_inode->i_sem);
+	dentry = lookup_hash(&nd.last, nd.dentry);
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		error = vfs_rmdir(nd.dentry->d_inode, dentry);
+		dput(dentry);
+	}
+	up(&nd.dentry->d_inode->i_sem);
+exit1:
+	dput(nd.dentry);
+	mntput(nd.mnt);
 exit:
-	return error;
-}
-
-asmlinkage long sys_rmdir(const char * pathname)
-{
-	int error;
-	char * tmp;
-
-	tmp = getname(pathname);
-	if(IS_ERR(tmp))
-		return PTR_ERR(tmp);
-	lock_kernel();
-	error = do_rmdir(tmp);
 	unlock_kernel();
-
-	putname(tmp);
-
+	putname(name);
 	return error;
 }
 
@@ -1216,42 +1244,50 @@
 	return error;
 }
 
-static int do_unlink(const char * name)
+asmlinkage long sys_unlink(const char * pathname)
 {
-	int error;
-	struct dentry *dir;
+	int error = 0;
+	char * name;
 	struct dentry *dentry;
+	struct nameidata nd;
 
-	dentry = lookup_dentry(name, LOOKUP_POSITIVE);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		goto exit;
-
-	dir = lock_parent(dentry);
-	error = -ENOENT;
-	if (check_parent(dir, dentry))
-		error = vfs_unlink(dir->d_inode, dentry);
+	name = getname(pathname);
+	if(IS_ERR(name))
+		return PTR_ERR(name);
+	lock_kernel();
 
-        unlock_dir(dir);
-	dput(dentry);
+	if (walk_init(name, LOOKUP_PARENT, &nd))
+		error = walk_name(name, &nd);
+	if (error)
+		goto exit;
+	error = -EISDIR;
+	if (nd.last_type != LAST_NORM)
+		goto exit1;
+	down(&nd.dentry->d_inode->i_sem);
+	dentry = lookup_hash(&nd.last, nd.dentry);
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		/* Why not before? Because we want correct error value */
+		if (nd.last.name[nd.last.len])
+			goto slashes;
+		error = vfs_unlink(nd.dentry->d_inode, dentry);
+	exit2:
+		dput(dentry);
+	}
+	up(&nd.dentry->d_inode->i_sem);
+exit1:
+	dput(nd.dentry);
+	mntput(nd.mnt);
 exit:
-	return error;
-}
-
-asmlinkage long sys_unlink(const char * pathname)
-{
-	int error;
-	char * tmp;
-
-	tmp = getname(pathname);
-	if(IS_ERR(tmp))
-		return PTR_ERR(tmp);
-	lock_kernel();
-	error = do_unlink(tmp);
 	unlock_kernel();
-	putname(tmp);
+	putname(name);
 
 	return error;
+
+slashes:
+	error = !dentry->d_inode ? -ENOENT :
+		S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
+	goto exit2;
 }
 
 int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
@@ -1468,6 +1504,8 @@
 			    &new_dir->i_zombie);
 	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
 	if (target) {
+		if (!error)
+			target->i_flags |= S_DEAD;
 		triple_up(&old_dir->i_zombie,
 			  &new_dir->i_zombie,
 			  &target->i_zombie);
@@ -1534,41 +1572,72 @@
 
 static inline int do_rename(const char * oldname, const char * newname)
 {
-	int error;
+	int error = 0;
 	struct dentry * old_dir, * new_dir;
 	struct dentry * old_dentry, *new_dentry;
+	struct nameidata oldnd, newnd;
 
-	old_dentry = lookup_dentry(oldname, LOOKUP_POSITIVE);
+	if (walk_init(oldname, LOOKUP_PARENT, &oldnd))
+		error = walk_name(oldname, &oldnd);
 
-	error = PTR_ERR(old_dentry);
-	if (IS_ERR(old_dentry))
+	if (error)
 		goto exit;
 
-	{
-		unsigned int flags = 0;
-		if (S_ISDIR(old_dentry->d_inode->i_mode))
-			flags = LOOKUP_SLASHOK;
-		new_dentry = lookup_dentry(newname, flags);
-	}
+	if (walk_init(newname, LOOKUP_PARENT, &newnd))
+		error = walk_name(newname, &newnd);
+	if (error)
+		goto exit1;
 
-	error = PTR_ERR(new_dentry);
-	if (IS_ERR(new_dentry))
-		goto exit_old;
+	error = -EXDEV;
+	if (oldnd.mnt != newnd.mnt)
+		goto exit2;
 
-	new_dir = get_parent(new_dentry);
-	old_dir = get_parent(old_dentry);
+	old_dir = oldnd.dentry;
+	error = -EBUSY;
+	if (oldnd.last_type != LAST_NORM)
+		goto exit2;
+
+	new_dir = newnd.dentry;
+	if (newnd.last_type != LAST_NORM)
+		goto exit2;
 
 	double_lock(new_dir, old_dir);
 
+	old_dentry = lookup_hash(&oldnd.last, old_dir);
+	error = PTR_ERR(old_dentry);
+	if (IS_ERR(old_dentry))
+		goto exit3;
+	/* source must exist */
 	error = -ENOENT;
-	if (check_parent(old_dir, old_dentry) && check_parent(new_dir, new_dentry))
-		error = vfs_rename(old_dir->d_inode, old_dentry,
+	if (!old_dentry->d_inode)
+		goto exit4;
+	/* unless the source is a directory trailing slashes give -ENOTDIR */
+	if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
+		error = -ENOTDIR;
+		if (oldnd.last.name[oldnd.last.len])
+			goto exit4;
+		if (newnd.last.name[newnd.last.len])
+			goto exit4;
+	}
+	new_dentry = lookup_hash(&newnd.last, new_dir);
+	error = PTR_ERR(new_dentry);
+	if (IS_ERR(new_dentry))
+		goto exit4;
+
+	error = vfs_rename(old_dir->d_inode, old_dentry,
 				   new_dir->d_inode, new_dentry);
 
-	double_unlock(new_dir, old_dir);
 	dput(new_dentry);
-exit_old:
+exit4:
 	dput(old_dentry);
+exit3:
+	double_up(&new_dir->d_inode->i_sem, &old_dir->d_inode->i_sem);
+exit2:
+	dput(newnd.dentry);
+	mntput(newnd.mnt);
+exit1:
+	dput(oldnd.dentry);
+	mntput(oldnd.mnt);
 exit:
 	return error;
 }
@@ -1620,11 +1689,11 @@
 	if (*link == '/') {
 		dput(nd->dentry);
 		mntput(nd->mnt);
-		if (!walk_init_root(link, LOOKUP_FOLLOW, nd))
+		if (!walk_init_root(link, nd))
 			/* weird __emul_prefix() stuff did it */
 			return 0;
 	}
-	return walk_name(link, LOOKUP_FOLLOW, nd);
+	return walk_name(link, nd);
 
 fail:
 	dput(nd->dentry);
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.3.99-pre5/linux/fs/nfs/dir.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfs/dir.c	Fri Apr 21 13:36:39 2000
@@ -891,7 +891,7 @@
 		dfprintk(VFS, "trying to rename %s to %s\n",
 			 dentry->d_name.name, silly);
 		
-		sdentry = lookup_one(silly, dget(dentry->d_parent));
+		sdentry = lookup_one(silly, dentry->d_parent);
 		/*
 		 * N.B. Better to return EBUSY here ... it could be
 		 * dangerous to delete the file while it's in use.
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.3.99-pre5/linux/fs/nfs/file.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfs/file.c	Tue Apr 25 17:28:55 2000
@@ -74,6 +74,11 @@
 
 	dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
+	/* Make sure all async reads have been sent off. We don't bother
+	 * waiting on them though... */
+	if (file->f_mode & FMODE_READ)
+		nfs_pagein_inode(inode, 0, 0);
+
 	status = nfs_wb_file(inode, file);
 	if (!status) {
 		status = file->f_error;
@@ -166,8 +171,36 @@
 	return status;
 }
 
+/*
+ * The following is used by wait_on_page(), generic_file_readahead()
+ * to initiate the completion of any page readahead operations.
+ */
+static int nfs_sync_page(struct page *page)
+{
+	struct inode	*inode = (struct inode *)page->mapping->host;
+	unsigned long	index = page_index(page);
+	unsigned int	rpages, wpages;
+	int		result;
+
+	if (!inode)
+		return 0;
+
+	rpages = NFS_SERVER(inode)->rpages;
+	result = nfs_pagein_inode(inode, index, rpages);
+	if (result < 0)
+		goto out_bad;
+	wpages = NFS_SERVER(inode)->wpages;
+	result = nfs_sync_file(inode, NULL, index, wpages, FLUSH_STABLE);
+	if (result < 0)
+		goto out_bad;
+	return 0;
+ out_bad:
+	return result;
+}
+
 struct address_space_operations nfs_file_aops = {
 	readpage: nfs_readpage,
+	sync_page: nfs_sync_page,
 	writepage: nfs_writepage,
 	prepare_write: nfs_prepare_write,
 	commit_write: nfs_commit_write
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/flushd.c linux/fs/nfs/flushd.c
--- v2.3.99-pre5/linux/fs/nfs/flushd.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfs/flushd.c	Tue Apr 25 17:28:55 2000
@@ -250,16 +250,18 @@
 		NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
 
 		if (flush) {
+			nfs_pagein_inode(inode, 0, 0);
 			nfs_sync_file(inode, NULL, 0, 0, FLUSH_AGING);
 		} else if (time_after(jiffies, NFS_NEXTSCAN(inode))) {
 			NFS_NEXTSCAN(inode) = jiffies + NFS_WRITEBACK_LOCKDELAY;
+			nfs_pagein_timeout(inode);
 			nfs_flush_timeout(inode, FLUSH_AGING);
 #ifdef CONFIG_NFS_V3
 			nfs_commit_timeout(inode, FLUSH_AGING);
 #endif
 		}
 
-		if (nfs_have_writebacks(inode)) {
+		if (nfs_have_writebacks(inode) || nfs_have_read(inode)) {
 			inode_append_flushd(inode);
 			if (time_after(delay, NFS_NEXTSCAN(inode)))
 				delay = NFS_NEXTSCAN(inode);
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.3.99-pre5/linux/fs/nfs/inode.c	Wed Apr 12 10:02:34 2000
+++ linux/fs/nfs/inode.c	Tue Apr 25 17:28:56 2000
@@ -101,9 +101,11 @@
 	inode->i_rdev = 0;
 	NFS_FILEID(inode) = 0;
 	NFS_FSID(inode) = 0;
+	INIT_LIST_HEAD(&inode->u.nfs_i.read);
 	INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
 	INIT_LIST_HEAD(&inode->u.nfs_i.commit);
 	INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
+	inode->u.nfs_i.nread = 0;
 	inode->u.nfs_i.ndirty = 0;
 	inode->u.nfs_i.ncommit = 0;
 	inode->u.nfs_i.npages = 0;
@@ -131,7 +133,7 @@
 	/*
 	 * The following can never actually happen...
 	 */
-	if (nfs_have_writebacks(inode)) {
+	if (nfs_have_writebacks(inode) || nfs_have_read(inode)) {
 		printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 	}
 
@@ -260,6 +262,7 @@
 	struct nfs_fsinfo	fsinfo;
 	int			tcp, version, maxlen;
 
+	memset(&sb->u.nfs_sb, 0, sizeof(sb->u.nfs_sb));
 	if (!data)
 		goto out_miss_args;
 
@@ -428,12 +431,20 @@
 		sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
 	if (server->rsize > fsinfo.rtmax)
 		server->rsize = fsinfo.rtmax;
-	if (server->rsize > PAGE_CACHE_SIZE)
-		server->rsize = PAGE_CACHE_SIZE;
 	if (server->wsize > fsinfo.wtmax)
 		server->wsize = fsinfo.wtmax;
-        if (server->wsize > NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT)
-                server->wsize = NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT;
+
+	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	if (server->rpages > NFS_READ_MAXIOV) {
+		server->rpages = NFS_READ_MAXIOV;
+		server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+	}
+
+	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+        if (server->wpages > NFS_WRITE_MAXIOV) {
+		server->wpages = NFS_WRITE_MAXIOV;
+                server->wsize = server->wpages << PAGE_CACHE_SHIFT;
+	}
 
         maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
 
@@ -1145,6 +1156,8 @@
 extern void nfs_destroy_fhcache(void);
 extern int nfs_init_nfspagecache(void);
 extern void nfs_destroy_nfspagecache(void);
+extern int nfs_init_readpagecache(void);
+extern int nfs_destroy_readpagecache(void);
 
 /*
  * Initialize NFS
@@ -1162,6 +1175,10 @@
 	if (err)
 		return err;
 
+	err = nfs_init_readpagecache();
+	if (err)
+		return err;
+
 #ifdef CONFIG_PROC_FS
 	rpc_proc_register(&nfs_rpcstat);
 #endif
@@ -1186,6 +1203,7 @@
 void
 cleanup_module(void)
 {
+	nfs_destroy_readpagecache();
 	nfs_destroy_nfspagecache();
 	nfs_destroy_fhcache();
 #ifdef CONFIG_PROC_FS
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c
--- v2.3.99-pre5/linux/fs/nfs/mount_clnt.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfs/mount_clnt.c	Thu Apr 13 07:54:19 2000
@@ -120,10 +120,12 @@
 static int
 xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	memset((u8 *)res, 0, sizeof(*res));
+	struct nfs_fh *fh = res->fh;
+
+	memset((void *)fh, 0, sizeof(*fh));
 	if ((res->status = ntohl(*p++)) == 0) {
-		res->fh->size = NFS2_FHSIZE;
-		memcpy(res->fh->data, p, NFS2_FHSIZE);
+		fh->size = NFS2_FHSIZE;
+		memcpy(fh->data, p, NFS2_FHSIZE);
 	}
 	return 0;
 }
@@ -131,12 +133,14 @@
 static int
 xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	memset((u8 *)res, 0, sizeof(*res));
+	struct nfs_fh *fh = res->fh;
+
+	memset((void *)fh, 0, sizeof(*fh));
 	if ((res->status = ntohl(*p++)) == 0) {
 		int size = ntohl(*p++);
 		if (size <= NFS3_FHSIZE) {
-			res->fh->size = size;
-			memcpy(res->fh->data, p, res->fh->size);
+			fh->size = size;
+			memcpy(fh->data, p, size);
 		} else
 			res->status = -EBADHANDLE;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.3.99-pre5/linux/fs/nfs/nfsroot.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfs/nfsroot.c	Fri Apr 21 13:36:40 2000
@@ -450,32 +450,16 @@
 	return status;
 }
 
-
 /*
- *  Now actually mount the given directory.
+ *  Get the NFS port numbers and file handle, and return the prepared 'data'
+ *  argument for ->read_super() if everything went OK. Return NULL otherwise.
  */
-static int __init root_nfs_do_mount(struct super_block *sb)
-{
-	/* Pass the server address to NFS */
-	set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port);
-
-	/* Now (finally ;-)) read the super block for mounting */
-	if (nfs_read_super(sb, &nfs_data, 1) == NULL)
-		return -1;
-	return 0;
-}
-
-
-/*
- *  Get the NFS port numbers and file handle, and then read the super-
- *  block for mounting.
- */
-int __init nfs_root_mount(struct super_block *sb)
+void * __init nfs_root_data(void)
 {
 	if (root_nfs_init() < 0
 	 || root_nfs_ports() < 0
-	 || root_nfs_get_handle() < 0
-	 || root_nfs_do_mount(sb) < 0)
-		return -1;
-	return 0;
+	 || root_nfs_get_handle() < 0)
+		return NULL;
+	set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port);
+	return (void*)&nfs_data;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.3.99-pre5/linux/fs/nfs/read.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfs/read.c	Tue Apr 25 17:28:56 2000
@@ -25,6 +25,8 @@
 #include <linux/pagemap.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
+#include <linux/nfs_flushd.h>
 #include <linux/smp_lock.h>
 
 #include <asm/segment.h>
@@ -32,54 +34,65 @@
 
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
-struct nfs_rreq {
-	struct inode *		ra_inode;	/* inode from which to read */
-	struct page *		ra_page;	/* page to be read */
-	struct nfs_readargs	ra_args;	/* XDR argument struct */
-	struct nfs_readres	ra_res;		/* ... and result struct */
-	struct nfs_fattr	ra_fattr;	/* fattr storage */
+struct nfs_read_data {
+	struct rpc_task		task;
+	struct dentry		*dentry;
+	struct rpc_cred		*cred;
+	struct nfs_readargs	args;	/* XDR argument struct */
+	struct nfs_readres	res;	/* ... and result struct */
+	struct nfs_fattr	fattr;	/* fattr storage */
+	struct list_head	pages;	/* Coalesced read requests */
 };
 
+/*
+ * Local function declarations
+ */
+static void	nfs_readpage_result(struct rpc_task *task);
+
 /* Hack for future NFS swap support */
 #ifndef IS_SWAPFILE
 # define IS_SWAPFILE(inode)	(0)
 #endif
 
+static kmem_cache_t *nfs_rdata_cachep = NULL;
 
-/*
- * Set up the NFS read request struct
- */
-static inline void
-nfs_readreq_setup(struct nfs_rreq *req, struct nfs_fh *fh,
-		  loff_t offset, void *buffer, unsigned int rsize)
+static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
 {
-	req->ra_args.fh     = fh;
-	req->ra_args.offset = offset;
-	req->ra_args.count  = rsize;
-	req->ra_args.iov[0].iov_base = (void *)buffer;
-	req->ra_args.iov[0].iov_len = rsize;
-	req->ra_args.nriov  = 1;
-	req->ra_fattr.valid = 0;
-	req->ra_res.fattr   = &req->ra_fattr;
-	req->ra_res.count   = rsize;
-	req->ra_res.eof     = 0;
+	struct nfs_read_data   *p;
+	p = kmem_cache_alloc(nfs_rdata_cachep, SLAB_NFS);
+	if (p) {
+		memset(p, 0, sizeof(*p));
+		INIT_LIST_HEAD(&p->pages);
+	}
+	return p;
 }
 
+static __inline__ void nfs_readdata_free(struct nfs_read_data *p)
+{
+	kmem_cache_free(nfs_rdata_cachep, p);
+}
+
+static void nfs_readdata_release(struct rpc_task *task)
+{
+        struct nfs_read_data   *data = (struct nfs_read_data *)task->tk_calldata;
+        nfs_readdata_free(data);
+}
 
 /*
  * Read a page synchronously.
  */
 static int
-nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
+nfs_readpage_sync(struct dentry *dentry, struct page *page)
 {
-	struct nfs_rreq	rqst;
-	struct rpc_message msg;
+	struct inode	*inode = dentry->d_inode;
+	struct nfs_fattr fattr;
 	loff_t		offset = page_offset(page);
 	char		*buffer;
 	int		rsize = NFS_SERVER(inode)->rsize;
-	int		result, refresh = 0;
+	int		result;
 	int		count = PAGE_CACHE_SIZE;
 	int		flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
+	int		eof;
 
 	dprintk("NFS: nfs_readpage_sync(%p)\n", page);
 
@@ -87,8 +100,7 @@
 	 * This works now because the socket layer never tries to DMA
 	 * into this buffer directly.
 	 */
-	buffer = (char *) kmap(page);	
-
+	buffer = (char *) kmap(page);
 	do {
 		if (count < rsize)
 			rsize = count;
@@ -98,16 +110,11 @@
 			dentry->d_parent->d_name.name, dentry->d_name.name,
 			(long long)offset, rsize, buffer);
 
-		/* Set up arguments and perform rpc call */
-		nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize);
 		lock_kernel();
-		msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
-		msg.rpc_argp = &rqst.ra_args;
-		msg.rpc_resp = &rqst.ra_res;
-		msg.rpc_cred = NULL;
-		result = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
+		result = NFS_PROTO(inode)->read(dentry, &fattr, flags, offset,
+						rsize, buffer, &eof);
 		unlock_kernel();
-		nfs_refresh_inode(inode, &rqst.ra_fattr);
+		nfs_refresh_inode(inode, &fattr);
 
 		/*
 		 * Even if we had a partial success we can't mark the page
@@ -118,7 +125,6 @@
 				result = -EINVAL;
 			goto io_error;
 		}
-		refresh = 1;
 		count  -= result;
 		offset += result;
 		buffer += result;
@@ -128,6 +134,8 @@
 
 	memset(buffer, 0, count);
 	SetPageUptodate(page);
+	if (PageError(page))
+		ClearPageError(page);
 	result = 0;
 
 io_error:
@@ -136,92 +144,318 @@
 	return result;
 }
 
+static inline struct nfs_page *
+_nfs_find_read(struct inode *inode, struct page *page)
+{
+	struct list_head	*head, *next;
+
+	head = &inode->u.nfs_i.read;
+	next = head->next;
+	while (next != head) {
+		struct nfs_page *req = nfs_list_entry(next);
+		next = next->next;
+		if (page_index(req->wb_page) != page_index(page))
+			continue;
+		req->wb_count++;
+		return req;
+	}
+	return NULL;
+}
+
+static struct nfs_page *
+nfs_find_read(struct inode *inode, struct page *page)
+{
+	struct nfs_page *req;
+	spin_lock(&nfs_wreq_lock);
+	req = _nfs_find_read(inode, page);
+	spin_unlock(&nfs_wreq_lock);
+	return req;
+}
+
 /*
- * This is the callback from RPC telling us whether a reply was
- * received or some error occurred (timeout or socket shutdown).
+ * Add a request to the inode's asynchronous read list.
  */
-static void
-nfs_readpage_result(struct rpc_task *task)
+static inline void
+nfs_mark_request_read(struct nfs_page *req)
 {
-	struct nfs_rreq	*req = (struct nfs_rreq *) task->tk_calldata;
-	struct page	*page = req->ra_page;
-	char		*address = req->ra_args.iov[0].iov_base;
-	int		result = task->tk_status;
-	static int	succ = 0, fail = 0;
-
-	dprintk("NFS: %4d received callback for page %p, result %d\n",
-			task->tk_pid, address, result);
-
-	nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
-	if (result >= 0) {
-		result = req->ra_res.count;
-		if (result < PAGE_CACHE_SIZE)
-			memset(address + result, 0, PAGE_CACHE_SIZE - result);
-		SetPageUptodate(page);
-		succ++;
-	} else {
-		SetPageError(page);
-		fail++;
-		dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
+	struct inode *inode = req->wb_dentry->d_inode;
+
+	spin_lock(&nfs_wreq_lock);
+	if (list_empty(&req->wb_list)) {
+		nfs_list_add_request(req, &inode->u.nfs_i.read);
+		inode->u.nfs_i.nread++;
+	}
+	spin_unlock(&nfs_wreq_lock);
+	/*
+	 * NB: the call to inode_schedule_scan() must lie outside the
+	 *     spinlock since it can run flushd().
+	 */
+	inode_schedule_scan(inode, req->wb_timeout);
+}
+
+static int
+nfs_readpage_async(struct dentry *dentry, struct page *page)
+{
+	struct inode	*inode = dentry->d_inode;
+	struct nfs_page	*req, *new = NULL;
+	int		result;
+
+	for (;;) {
+		result = 0;
+		if (Page_Uptodate(page))
+			break;
+
+		req = nfs_find_read(inode, page);
+		if (req) {
+			if (page != req->wb_page) {
+				nfs_release_request(req);
+				nfs_pagein_inode(inode, page_index(page), 0);
+				continue;
+			}
+			nfs_release_request(req);
+			break;
+		}
+
+		if (new) {
+			nfs_lock_request(new);
+			new->wb_timeout = jiffies + NFS_READ_DELAY;
+			nfs_mark_request_read(new);
+			nfs_unlock_request(new);
+			new = NULL;
+			break;
+		}
+
+		result = -ENOMEM;
+		new = nfs_create_request(dentry, page, 0, PAGE_CACHE_SIZE);
+		if (!new)
+			break;
 	}
-	kunmap(page);
-	UnlockPage(page);
-	page_cache_release(page);
 
-	kfree(req);
+	if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+	    page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
+		nfs_pagein_inode(inode, 0, 0);
+	if (new)
+		nfs_release_request(new);
+	return result;
 }
 
-static inline int
-nfs_readpage_async(struct dentry *dentry, struct inode *inode,
-			struct page *page)
+/*
+ * Set up the NFS read request struct
+ */
+static void
+nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
 {
-	struct rpc_message msg;
-	unsigned long address;
-	struct nfs_rreq	*req;
-	int		result = -1, flags;
+	struct nfs_page		*req;
+	struct iovec		*iov;
+	unsigned int		count;
+
+	iov = data->args.iov;
+	count = 0;
+	while (!list_empty(head)) {
+		struct nfs_page *req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, &data->pages);
+		iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset);
+		iov->iov_len = req->wb_bytes;
+		count += req->wb_bytes;
+		iov++;
+		data->args.nriov++;
+	}
+	req = nfs_list_entry(data->pages.next);
+	data->dentry	  = req->wb_dentry;
+	data->cred	  = req->wb_cred;
+	data->args.fh     = NFS_FH(req->wb_dentry);
+	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.count  = count;
+	data->res.fattr   = &data->fattr;
+	data->res.count   = count;
+	data->res.eof     = 0;
+}
+
+static void
+nfs_async_read_error(struct list_head *head)
+{
+	struct nfs_page	*req;
+	struct page	*page;
 
-	dprintk("NFS: nfs_readpage_async(%p)\n", page);
-	if (NFS_CONGESTED(inode))
-		goto out_defer;
+	while (!list_empty(head)) {
+		req = nfs_list_entry(head->next);
+		page = req->wb_page;
+		nfs_list_remove_request(req);
+		SetPageError(page);
+		UnlockPage(page);
+		nfs_unlock_request(req);
+		nfs_release_request(req);
+	}
+}
+
+static int
+nfs_pagein_one(struct list_head *head, struct dentry *dentry)
+{
+	struct inode		*inode = dentry->d_inode;
+	struct rpc_task		*task;
+	struct rpc_clnt		*clnt = NFS_CLIENT(inode);
+	struct nfs_read_data	*data;
+	struct rpc_message	msg;
+	int			flags;
+	sigset_t		oldset;
+
+	data = nfs_readdata_alloc();
+	if (!data)
+		goto out_bad;
+	task = &data->task;
 
 	/* N.B. Do we need to test? Never called for swapfile inode */
 	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
-	req = (struct nfs_rreq *) rpc_allocate(flags, sizeof(*req));
-	if (!req)
-		goto out_defer;
-
-	address = kmap(page);	
-	/* Initialize request */
-	/* N.B. Will the dentry remain valid for life of request? */
-	nfs_readreq_setup(req, NFS_FH(dentry), page_offset(page),
-				(void *) address, PAGE_CACHE_SIZE);
-	req->ra_inode = inode;
-	req->ra_page = page; /* count has been incremented by caller */
 
-	/* Start the async call */
-	dprintk("NFS: executing async READ request.\n");
+	nfs_read_rpcsetup(head, data);
 
+	/* Finalize the task. */
+	rpc_init_task(task, clnt, nfs_readpage_result, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_readdata_release;
+
+#ifdef CONFIG_NFS_V3
 	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
-	msg.rpc_argp = &req->ra_args;
-	msg.rpc_resp = &req->ra_res;
-	msg.rpc_cred = NULL;
-
-	result = rpc_call_async(NFS_CLIENT(inode), &msg, flags,
-				nfs_readpage_result, req);
-	if (result < 0)
-		goto out_free;
-	result = 0;
-out:
-	return result;
+#else
+	msg.rpc_proc = NFSPROC_READ;
+#endif
+	msg.rpc_argp = &data->args;
+	msg.rpc_resp = &data->res;
+	msg.rpc_cred = data->cred;
 
-out_defer:
-	dprintk("NFS: deferring async READ request.\n");
-	goto out;
-out_free:
-	dprintk("NFS: failed to enqueue async READ request.\n");
-	kunmap(page);
-	kfree(req);
-	goto out;
+	/* Start the async call */
+	dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n",
+		task->tk_pid,
+		dentry->d_parent->d_name.name, dentry->d_name.name,
+		data->args.count, data->args.nriov);
+
+	rpc_clnt_sigmask(clnt, &oldset);
+	rpc_call_setup(task, &msg, 0);
+	rpc_execute(task);
+	rpc_clnt_sigunmask(clnt, &oldset);
+	return 0;
+out_bad:
+	nfs_async_read_error(head);
+	return -ENOMEM;
+}
+
+static int
+nfs_pagein_list(struct inode *inode, struct list_head *head)
+{
+	LIST_HEAD(one_request);
+	struct nfs_page		*req;
+	int			error = 0;
+	unsigned int		pages = 0,
+				rpages = NFS_SERVER(inode)->rpages;
+
+	while (!list_empty(head)) {
+		pages += nfs_coalesce_requests(head, &one_request, rpages);
+		req = nfs_list_entry(one_request.next);
+		error = nfs_pagein_one(&one_request, req->wb_dentry);
+		if (error < 0)
+			break;
+	}
+	if (error >= 0)
+		return pages;
+
+	nfs_async_read_error(head);
+	return error;
+}
+
+static int
+nfs_scan_read_timeout(struct inode *inode, struct list_head *dst)
+{
+	int	pages;
+	spin_lock(&nfs_wreq_lock);
+	pages = nfs_scan_list_timeout(&inode->u.nfs_i.read, dst, inode);
+	inode->u.nfs_i.nread -= pages;
+	if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read))
+		printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n");
+	spin_unlock(&nfs_wreq_lock);
+	return pages;
+}
+
+static int
+nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+{
+	int	res;
+	spin_lock(&nfs_wreq_lock);
+	res = nfs_scan_list(&inode->u.nfs_i.read, dst, NULL, idx_start, npages);
+	inode->u.nfs_i.nread -= res;
+	if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read))
+		printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n");
+	spin_unlock(&nfs_wreq_lock);
+	return res;
+}
+
+int nfs_pagein_inode(struct inode *inode, unsigned long idx_start,
+		     unsigned int npages)
+{
+	LIST_HEAD(head);
+	int	res,
+		error = 0;
+
+	res = nfs_scan_read(inode, &head, idx_start, npages);
+	if (res)
+		error = nfs_pagein_list(inode, &head);
+	if (error < 0)
+		return error;
+	return res;
+}
+
+int nfs_pagein_timeout(struct inode *inode)
+{
+	LIST_HEAD(head);
+	int	pages,
+		error = 0;
+
+	pages = nfs_scan_read_timeout(inode, &head);
+	if (pages)
+		error = nfs_pagein_list(inode, &head);
+	if (error < 0)
+		return error;
+	return pages;
+}
+
+/*
+ * This is the callback from RPC telling us whether a reply was
+ * received or some error occurred (timeout or socket shutdown).
+ */
+static void
+nfs_readpage_result(struct rpc_task *task)
+{
+	struct nfs_read_data	*data = (struct nfs_read_data *) task->tk_calldata;
+	struct dentry		*dentry = data->dentry;
+	struct inode		*inode = dentry->d_inode;
+	int			count = data->res.count;
+
+	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	nfs_refresh_inode(inode, &data->fattr);
+	while (!list_empty(&data->pages)) {
+		struct nfs_page *req = nfs_list_entry(data->pages.next);
+		struct page *page = req->wb_page;
+		nfs_list_remove_request(req);
+
+		if (task->tk_status >= 0 && count >= 0) {
+			SetPageUptodate(page);
+			count -= PAGE_CACHE_SIZE;
+		} else
+			SetPageError(page);
+		kunmap(page);
+		UnlockPage(page);
+
+		dprintk("NFS: read (%s/%s %d@%Ld)\n",
+                        req->wb_dentry->d_parent->d_name.name,
+                        req->wb_dentry->d_name.name,
+                        req->wb_bytes,
+                        (long long)(page_offset(page) + req->wb_offset));
+		nfs_unlock_request(req);
+		nfs_release_request(req);
+	}
 }
 
 /*
@@ -242,11 +476,8 @@
 	struct inode *inode = dentry->d_inode;
 	int		error;
 
-	lock_kernel();
 	dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
 		page, PAGE_CACHE_SIZE, page->index);
-	get_page(page);
-
 	/*
 	 * Try to flush any pending writes to the file..
 	 *
@@ -259,22 +490,36 @@
 		goto out_error;
 
 	error = -1;
-	if (!IS_SWAPFILE(inode) && !PageError(page) &&
-	    NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
-		error = nfs_readpage_async(dentry, inode, page);
+	if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
+		error = nfs_readpage_async(dentry, page);
 	if (error >= 0)
 		goto out;
 
-	error = nfs_readpage_sync(dentry, inode, page);
+	error = nfs_readpage_sync(dentry, page);
 	if (error < 0 && IS_SWAPFILE(inode))
 		printk("Aiee.. nfs swap-in of page failed!\n");
-	goto out_free;
+out:
+	return error;
 
 out_error:
 	UnlockPage(page);
-out_free:
-	page_cache_release(page);
-out:
-	unlock_kernel();
-	return error;
+	goto out;
+}
+
+int nfs_init_readpagecache(void)
+{
+	nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
+					     sizeof(struct nfs_read_data),
+					     0, SLAB_HWCACHE_ALIGN,
+					     NULL, NULL);
+	if (nfs_rdata_cachep == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void nfs_destroy_readpagecache(void)
+{
+	if (kmem_cache_destroy(nfs_rdata_cachep))
+		printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.3.99-pre5/linux/fs/nfs/write.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfs/write.c	Wed Apr 26 08:49:00 2000
@@ -57,6 +57,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs_flushd.h>
+#include <linux/nfs_page.h>
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
 
@@ -72,16 +73,11 @@
 /*
  * Local structures
  *
- * Valid flags for a dirty buffer
- */
-#define PG_BUSY			0x0001
-
-/*
  * This is the struct where the WRITE/COMMIT arguments go.
  */
 struct nfs_write_data {
 	struct rpc_task		task;
-	struct file		*file;
+	struct dentry		*dentry;
 	struct rpc_cred		*cred;
 	struct nfs_writeargs	args;		/* argument struct */
 	struct nfs_writeres	res;		/* result struct */
@@ -90,27 +86,13 @@
 	struct list_head	pages;		/* Coalesced requests we wish to flush */
 };
 
-struct nfs_page {
-	struct list_head	wb_hash,	/* Inode */
-				wb_list,
-				*wb_list_head;
-	struct file		*wb_file;
-	struct rpc_cred		*wb_cred;
-	struct page		*wb_page;	/* page to write out */
-	wait_queue_head_t	wb_wait;	/* wait queue */
-	unsigned long		wb_timeout;	/* when to write/commit */
-	unsigned int		wb_offset,	/* Offset of write */
-				wb_bytes,	/* Length of request */
-				wb_count,	/* reference count */
-				wb_flags;
-	struct nfs_writeverf	wb_verf;	/* Commit cookie */
-};
-
-#define NFS_WBACK_BUSY(req)	((req)->wb_flags & PG_BUSY)
-
 /*
  * Local function declarations
  */
+static struct nfs_page * nfs_update_request(struct file*, struct dentry *,
+					    struct page *page,
+					    unsigned int, unsigned int);
+static void	nfs_strategy(struct inode *inode);
 static void	nfs_writeback_done(struct rpc_task *);
 #ifdef CONFIG_NFS_V3
 static void	nfs_commit_done(struct rpc_task *);
@@ -186,9 +168,10 @@
  * Offset is the data offset within the page.
  */
 static int
-nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
-		struct page *page, unsigned long offset, unsigned int count)
+nfs_writepage_sync(struct dentry *dentry, struct page *page,
+		   unsigned int offset, unsigned int count)
 {
+	struct inode	*inode = dentry->d_inode;
 	loff_t		base;
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
 	int		result, refresh = 0, written = 0, flags;
@@ -197,9 +180,9 @@
 	struct nfs_writeverf verf;
 
 	lock_kernel();
-	dprintk("NFS:      nfs_writepage_sync(%s/%s %d@%lu/%ld)\n",
+	dprintk("NFS:      nfs_writepage_sync(%s/%s %d@%Ld)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		count, page->index, offset);
+		count, (long long)(page_offset(page) + offset));
 
 	buffer = (u8 *) kmap(page) + offset;
 	base = page_offset(page) + offset;
@@ -235,6 +218,9 @@
 			inode->i_size = base;
 	} while (count);
 
+	if (PageError(page))
+		ClearPageError(page);
+
 io_error:
 	kunmap(page);
 
@@ -242,14 +228,28 @@
 	return written? written : result;
 }
 
+static int
+nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page,
+		    unsigned int offset, unsigned int count)
+{
+	struct nfs_page	*req;
+	int		status;
+
+	req = nfs_update_request(file, dentry, page, offset, count);
+	status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
+	if (status < 0)
+		goto out;
+	nfs_release_request(req);
+	nfs_strategy(dentry->d_inode);
+ out:
+	return status;
+}
+
 /*
- * Write a page to the server. This was supposed to be used for
- * NFS swapping only.
- * FIXME: Using this for mmap is pointless, breaks asynchronous
- *        writebacks, and is extremely slow.
+ * Write an mmapped page to the server.
  */
 int
-nfs_writepage(struct dentry * dentry, struct page *page)
+nfs_writepage(struct file *file, struct dentry * dentry, struct page *page)
 {
 	struct inode *inode = dentry->d_inode;
 	unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
@@ -265,9 +265,17 @@
 	if (page->index >= end_index+1 || !offset)
 		return -EIO;
 do_it:
-	err = nfs_writepage_sync(dentry, inode, page, 0, offset); 
-	if ( err == offset) return 0; 
+	if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
+		err = nfs_writepage_async(file, dentry, page, 0, offset);
+		if (err >= 0)
+			goto out_ok;
+	}
+	err = nfs_writepage_sync(dentry, page, 0, offset); 
+	if ( err == offset)
+		goto out_ok;
 	return err; 
+ out_ok:
+	return 0;
 }
 
 /*
@@ -297,12 +305,6 @@
 	return 0;
 }
 
-static inline struct nfs_page *
-nfs_inode_wb_entry(struct list_head *head)
-{
-	return list_entry(head, struct nfs_page, wb_hash);
-}
-
 /*
  * Insert a write request into an inode
  */
@@ -332,13 +334,13 @@
 	}
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
-	inode = req->wb_file->f_dentry->d_inode;
+	inode = req->wb_dentry->d_inode;
 	list_del(&req->wb_hash);
 	INIT_LIST_HEAD(&req->wb_hash);
 	inode->u.nfs_i.npages--;
 	if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
-	if (!nfs_have_writebacks(inode))
+	if (!nfs_have_writebacks(inode) && !nfs_have_read(inode))
 		inode_remove_flushd(inode);
 	spin_unlock(&nfs_wreq_lock);
 	nfs_release_request(req);
@@ -365,7 +367,7 @@
 	return NULL;
 }
 
-struct nfs_page *
+static struct nfs_page *
 nfs_find_request(struct inode *inode, struct page *page)
 {
 	struct nfs_page		*req;
@@ -376,17 +378,10 @@
 	return req;
 }
 
-static inline struct nfs_page *
-nfs_list_entry(struct list_head *head)
-{
-	return list_entry(head, struct nfs_page, wb_list);
-}
-
 /*
  * Insert a write request into a sorted list
  */
-static inline void
-nfs_list_add_request(struct nfs_page *req, struct list_head *head)
+void nfs_list_add_request(struct nfs_page *req, struct list_head *head)
 {
 	struct list_head *prev;
 
@@ -394,10 +389,6 @@
 		printk(KERN_ERR "NFS: Add to list failed!\n");
 		return;
 	}
-	if (list_empty(&req->wb_hash)) {
-		printk(KERN_ERR "NFS: Unhashed request attempted added to a list!\n");
-		return;
-	}
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted added to list!\n");
 	prev = head->prev;
@@ -414,8 +405,7 @@
 /*
  * Insert a write request into an inode
  */
-static inline void
-nfs_list_remove_request(struct nfs_page *req)
+void nfs_list_remove_request(struct nfs_page *req)
 {
 	if (list_empty(&req->wb_list))
 		return;
@@ -432,7 +422,7 @@
 static inline void
 nfs_mark_request_dirty(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_file->f_dentry->d_inode;
+	struct inode *inode = req->wb_dentry->d_inode;
 
 	spin_lock(&nfs_wreq_lock);
 	if (list_empty(&req->wb_list)) {
@@ -453,7 +443,7 @@
 static inline int
 nfs_dirty_request(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_file->f_dentry->d_inode;
+	struct inode *inode = req->wb_dentry->d_inode;
 	return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
 }
 
@@ -464,7 +454,7 @@
 static inline void
 nfs_mark_request_commit(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_file->f_dentry->d_inode;
+	struct inode *inode = req->wb_dentry->d_inode;
 
 	spin_lock(&nfs_wreq_lock);
 	if (list_empty(&req->wb_list)) {
@@ -481,40 +471,15 @@
 #endif
 
 /*
- * Lock the page of an asynchronous request
- */
-static inline int
-nfs_lock_request(struct nfs_page *req)
-{
-	if (NFS_WBACK_BUSY(req))
-		return 0;
-	req->wb_count++;
-	req->wb_flags |= PG_BUSY;
-	return 1;
-}
-
-static inline void
-nfs_unlock_request(struct nfs_page *req)
-{
-	if (!NFS_WBACK_BUSY(req)) {
-		printk(KERN_ERR "NFS: Invalid unlock attempted\n");
-		return;
-	}
-	req->wb_flags &= ~PG_BUSY;
-	wake_up(&req->wb_wait);
-	nfs_release_request(req);
-}
-
-/*
  * Create a write request.
  * Page must be locked by the caller. This makes sure we never create
  * two different requests for the same page, and avoids possible deadlock
  * when we reach the hard limit on the number of dirty pages.
  */
-static struct nfs_page *
-nfs_create_request(struct inode *inode, struct file *file, struct page *page,
-		   unsigned int offset, unsigned int count)
+struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page,
+				    unsigned int offset, unsigned int count)
 {
+	struct inode		*inode = dentry->d_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct nfs_page		*req = NULL;
 	long			timeout;
@@ -522,11 +487,7 @@
 	/* Deal with hard/soft limits.
 	 */
 	do {
-		/* If we're over the soft limit, flush out old requests */
-		if (nfs_nr_requests >= MAX_REQUEST_SOFT)
-			nfs_wb_file(inode, file);
-
-		/* If we're still over the soft limit, wake up some requests */
+		/* If we're over the global soft limit, wake up all requests */
 		if (nfs_nr_requests >= MAX_REQUEST_SOFT) {
 			dprintk("NFS:      hit soft limit (%d requests)\n",
 				nfs_nr_requests);
@@ -535,9 +496,9 @@
 			nfs_wake_flushd();
 		}
 
-		/* If we haven't reached the hard limit yet,
+		/* If we haven't reached the local hard limit yet,
 		 * try to allocate the request struct */
-		if (nfs_nr_requests < MAX_REQUEST_HARD) {
+		if (cache->nr_requests < MAX_REQUEST_HARD) {
 			req = nfs_page_alloc();
 			if (req != NULL)
 				break;
@@ -545,7 +506,7 @@
 
 		/* We're over the hard limit. Wait for better times */
 		dprintk("NFS:      create_request sleeping (total %d pid %d)\n",
-			nfs_nr_requests, current->pid);
+			cache->nr_requests, current->pid);
 
 		timeout = 1 * HZ;
 		if (NFS_SERVER(inode)->flags & NFS_MOUNT_INTR) {
@@ -557,7 +518,7 @@
 			sleep_on_timeout(&cache->request_wait, timeout);
 
 		dprintk("NFS:      create_request waking up (tot %d pid %d)\n",
-			nfs_nr_requests, current->pid);
+			cache->nr_requests, current->pid);
 	} while (!req);
 	if (!req)
 		return NULL;
@@ -566,17 +527,11 @@
 	 * long write-back delay. This will be adjusted in
 	 * update_nfs_request below if the region is not locked. */
 	req->wb_page    = page;
-	atomic_inc(&page->count);
+	get_page(page);
 	req->wb_offset  = offset;
 	req->wb_bytes   = count;
-	/* If the region is locked, adjust the timeout */
-	if (region_locked(inode, req))
-		req->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
-	else
-		req->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;
-	req->wb_file    = file;
+	req->wb_dentry  = dget(dentry);
 	req->wb_cred	= rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
-	get_file(file);
 	req->wb_count   = 1;
 
 	/* register request's existence */
@@ -595,7 +550,7 @@
 void
 nfs_release_request(struct nfs_page *req)
 {
-	struct inode		*inode = req->wb_file->f_dentry->d_inode;
+	struct inode		*inode = req->wb_dentry->d_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct page		*page = req->wb_page;
 
@@ -618,7 +573,11 @@
 		printk(KERN_ERR "NFS: Request released while still locked!\n");
 
 	rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
-	fput(req->wb_file);
+	lock_kernel();
+	if (req->wb_file)
+		fput(req->wb_file);
+	dput(req->wb_dentry);
+	unlock_kernel();
 	page_cache_release(page);
 	nfs_page_free(req);
 	/* wake up anyone waiting to allocate a request */
@@ -635,7 +594,7 @@
 static int
 nfs_wait_on_request(struct nfs_page *req)
 {
-	struct inode	*inode = req->wb_file->f_dentry->d_inode;
+	struct inode	*inode = req->wb_dentry->d_inode;
         struct rpc_clnt	*clnt = NFS_CLIENT(inode);
         int retval;
 
@@ -701,8 +660,7 @@
  * Scan cluster for dirty pages and send as many of them to the
  * server as possible.
  */
-static int
-nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode)
+int nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode)
 {
 	struct list_head	*p;
         struct nfs_page		*req;
@@ -754,8 +712,7 @@
 }
 #endif
 
-static int
-nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+int nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
 {
 	struct list_head	*p;
 	struct nfs_page		*req;
@@ -819,8 +776,7 @@
 #endif
 
 
-static int
-coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages)
+int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages)
 {
 	struct nfs_page		*req = NULL;
 	unsigned int		pages = 0;
@@ -832,7 +788,10 @@
 		if (prev) {
 			if (req->wb_file != prev->wb_file)
 				break;
-
+			if (req->wb_dentry != prev->wb_dentry)
+				break;
+			if (req->wb_cred != prev->wb_cred)
+				break;
 			if (page_index(req->wb_page) != page_index(prev->wb_page)+1)
 				break;
 
@@ -858,10 +817,10 @@
  * Note: Should always be called with the Page Lock held!
  */
 static struct nfs_page *
-nfs_update_request(struct file* file, struct page *page,
-		   unsigned long offset, unsigned int bytes)
+nfs_update_request(struct file* file, struct dentry *dentry, struct page *page,
+		   unsigned int offset, unsigned int bytes)
 {
-	struct inode		*inode = file->f_dentry->d_inode;
+	struct inode		*inode = dentry->d_inode;
 	struct nfs_page		*req, *new = NULL;
 	unsigned long		rqend, end;
 
@@ -896,12 +855,26 @@
 		}
 		spin_unlock(&nfs_wreq_lock);
 
+
 		/* Create the request. It's safe to sleep in this call because
 		 * we only get here if the page is locked.
+		 *
+		 * If we're over the soft limit, flush out old requests
 		 */
-		new = nfs_create_request(inode, file, page, offset, bytes);
+		if (file && nfs_nr_requests >= MAX_REQUEST_SOFT)
+			nfs_wb_file(inode, file);
+		new = nfs_create_request(dentry, page, offset, bytes);
 		if (!new)
 			return ERR_PTR(-ENOMEM);
+		if (file) {
+			new->wb_file = file;
+			get_file(file);
+		}
+		/* If the region is locked, adjust the timeout */
+		if (region_locked(inode, new))
+			new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
+		else
+			new->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;
 	}
 
 	/* We have a request for our page.
@@ -956,31 +929,33 @@
  */
 #define NFS_STRATEGY_PAGES      8
 static void
-nfs_strategy(struct file *file)
+nfs_strategy(struct inode *inode)
 {
-	struct inode	*inode = file->f_dentry->d_inode;
 	unsigned int	dirty, wpages;
 
 	dirty  = inode->u.nfs_i.ndirty;
-	wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT;
+	wpages = NFS_SERVER(inode)->wpages;
 #ifdef CONFIG_NFS_V3
 	if (NFS_PROTO(inode)->version == 2) {
 		if (dirty >= NFS_STRATEGY_PAGES * wpages)
-			nfs_flush_file(inode, file, 0, 0, 0);
+			nfs_flush_file(inode, NULL, 0, 0, 0);
 	} else {
 		if (dirty >= wpages)
-			nfs_flush_file(inode, file, 0, 0, 0);
+			nfs_flush_file(inode, NULL, 0, 0, 0);
+		if (inode->u.nfs_i.ncommit > NFS_STRATEGY_PAGES * wpages &&
+		    nfs_nr_requests > MAX_REQUEST_SOFT)
+			nfs_commit_file(inode, NULL, 0, 0, 0);
 	}
 #else
 	if (dirty >= NFS_STRATEGY_PAGES * wpages)
-		nfs_flush_file(inode, file, 0, 0, 0);
+		nfs_flush_file(inode, NULL, 0, 0, 0);
 #endif
 	/*
-	 * If we're running out of requests, flush out everything
+	 * If we're running out of free requests, flush out everything
 	 * in order to reduce memory useage...
 	 */
-	if (nfs_nr_requests > MAX_REQUEST_SOFT)
-		nfs_wb_file(inode, file);
+	if (inode->u.nfs_i.npages > MAX_REQUEST_SOFT)
+		nfs_wb_all(inode);
 }
 
 int
@@ -1013,7 +988,7 @@
  * things with a page scheduled for an RPC call (e.g. invalidate it).
  */
 int
-nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count)
+nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count)
 {
 	struct dentry	*dentry = file->f_dentry;
 	struct inode	*inode = dentry->d_inode;
@@ -1030,7 +1005,7 @@
 	 * page synchronously.
 	 */
 	if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
-		return nfs_writepage_sync(dentry, inode, page, offset, count);
+		return nfs_writepage_sync(dentry, page, offset, count);
 
 	/*
 	 * Try to find an NFS request corresponding to this page
@@ -1039,7 +1014,7 @@
 	 * it out now.
 	 */
 	do {
-		req = nfs_update_request(file, page, offset, count);
+		req = nfs_update_request(file, dentry, page, offset, count);
 		status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
 		if (status != -EBUSY)
 			break;
@@ -1066,7 +1041,7 @@
 		 * of requests.
 		 */
 		if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE)
-			nfs_strategy(file);
+			nfs_strategy(inode);
 	}
 	nfs_release_request(req);
 done:
@@ -1103,9 +1078,9 @@
 		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->file = req->wb_file;
+	data->dentry = req->wb_dentry;
 	data->cred = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_file->f_dentry);
+	data->args.fh     = NFS_FH(req->wb_dentry);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
@@ -1123,9 +1098,8 @@
  * that has been written but not committed.
  */
 static int
-nfs_flush_one(struct list_head *head, struct file *file, int how)
+nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
 {
-	struct dentry           *dentry = file->f_dentry;
 	struct inode            *inode = dentry->d_inode;
 	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
 	struct nfs_write_data	*data;
@@ -1198,12 +1172,12 @@
 	struct nfs_page		*req;
 	int			error = 0;
 	unsigned int		pages = 0,
-				wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT;
+				wpages = NFS_SERVER(inode)->wpages;
 
 	while (!list_empty(head)) {
-		pages += coalesce_requests(head, &one_request, wpages);
+		pages += nfs_coalesce_requests(head, &one_request, wpages);
 		req = nfs_list_entry(one_request.next);
-		error = nfs_flush_one(&one_request, req->wb_file, how);
+		error = nfs_flush_one(&one_request, req->wb_dentry, how);
 		if (error < 0)
 			break;
 	}
@@ -1229,9 +1203,10 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
 	struct nfs_writeargs	*argp = &data->args;
 	struct nfs_writeres	*resp = &data->res;
-	struct dentry		*dentry = data->file->f_dentry;
+	struct dentry		*dentry = data->dentry;
 	struct inode		*inode = dentry->d_inode;
 	struct nfs_page		*req;
+	struct page		*page;
 
 	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
 		task->tk_pid, task->tk_status);
@@ -1276,17 +1251,21 @@
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
+		page = req->wb_page;
 
-		kunmap(req->wb_page);
+		kunmap(page);
 
 		dprintk("NFS: write (%s/%s %d@%Ld)",
-			req->wb_file->f_dentry->d_parent->d_name.name,
-			req->wb_file->f_dentry->d_name.name,
+			req->wb_dentry->d_parent->d_name.name,
+			req->wb_dentry->d_name.name,
 			req->wb_bytes,
-			(long long)(page_offset(req->wb_page) + req->wb_offset));
+			(long long)(page_offset(page) + req->wb_offset));
 
 		if (task->tk_status < 0) {
-			req->wb_file->f_error = task->tk_status;
+			ClearPageUptodate(page);
+			SetPageError(page);
+			if (req->wb_file)
+				req->wb_file->f_error = task->tk_status;
 			nfs_inode_remove_request(req);
 			dprintk(", error = %d\n", task->tk_status);
 			goto next;
@@ -1329,9 +1308,9 @@
 	end = 0;
 	start = ~0;
 	req = nfs_list_entry(head->next);
-	data->file = req->wb_file;
+	dentry = req->wb_dentry;
+	data->dentry = dentry;
 	data->cred = req->wb_cred;
-	dentry = data->file->f_dentry;
 	inode = dentry->d_inode;
 	while (!list_empty(head)) {
 		struct nfs_page	*req;
@@ -1364,7 +1343,6 @@
 nfs_commit_list(struct list_head *head, int how)
 {
 	struct rpc_message	msg;
-	struct file		*file;
 	struct rpc_clnt		*clnt;
 	struct nfs_write_data	*data;
 	struct rpc_task         *task;
@@ -1384,8 +1362,7 @@
 	/* Set up the argument struct */
 	nfs_commit_rpcsetup(head, data);
 	req = nfs_list_entry(data->pages.next);
-	file = req->wb_file;
-	clnt = NFS_CLIENT(file->f_dentry->d_inode);
+	clnt = NFS_CLIENT(req->wb_dentry->d_inode);
 
 	rpc_init_task(task, clnt, nfs_commit_done, flags);
 	task->tk_calldata = data;
@@ -1422,7 +1399,7 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;
 	struct nfs_writeres	*resp = &data->res;
 	struct nfs_page		*req;
-	struct dentry		*dentry = data->file->f_dentry;
+	struct dentry		*dentry = data->dentry;
 	struct inode		*inode = dentry->d_inode;
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
@@ -1434,12 +1411,13 @@
 		nfs_list_remove_request(req);
 
 		dprintk("NFS: commit (%s/%s %d@%Ld)",
-			req->wb_file->f_dentry->d_parent->d_name.name,
-			req->wb_file->f_dentry->d_name.name,
+			req->wb_dentry->d_parent->d_name.name,
+			req->wb_dentry->d_name.name,
 			req->wb_bytes,
 			(long long)(page_offset(req->wb_page) + req->wb_offset));
 		if (task->tk_status < 0) {
-			req->wb_file->f_error = task->tk_status;
+			if (req->wb_file)
+				req->wb_file->f_error = task->tk_status;
 			nfs_inode_remove_request(req);
 			dprintk(", error = %d\n", task->tk_status);
 			goto next;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.3.99-pre5/linux/fs/nfsd/export.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfsd/export.c	Mon Apr 24 13:40:52 2000
@@ -103,23 +103,6 @@
 	return exp;
 }
 
-
-/*
- * Look up the device of the parent fs.
- */
-static inline int
-nfsd_parentdev(kdev_t *devp)
-{
-	struct super_block	*sb;
-
-	if (!(sb = get_super(*devp)) || !sb->s_root->d_covers)
-		return 0;
-	if (*devp == sb->s_root->d_covers->d_inode->i_dev)
-		return 0;
-	*devp = sb->s_root->d_covers->d_inode->i_dev;
-	return 1;
-}
-
 /*
  * Find the export entry for a given dentry.  <gam3@acm.org>
  */
@@ -127,36 +110,13 @@
 exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry)
 {
 	svc_export      *exp;
-	kdev_t		xdev = dev;
-	struct dentry	*xdentry = dentry;
-	struct dentry	*ndentry = NULL;
 
-	if (clp == NULL || dentry == NULL)
+	if (clp == NULL)
 		return NULL;
 
-	do {
-		xdev = dev;
-		do {
-			exp = clp->cl_export[EXPORT_HASH(xdev)];
-			if (exp)
-				do {
-					ndentry = exp->ex_dentry;
-				        if (ndentry == xdentry) {
-#ifdef NFSD_PARANOIA
-if (dev == xdev)
-	dprintk("nfsd: exp_parent submount over mount.\n");
-else
-	dprintk("nfsd: exp_parent found.\n");
-#endif
-						goto out;
-					}
-				} while (NULL != (exp = exp->ex_next));
-		} while (nfsd_parentdev(&xdev));
-		if (IS_ROOT(xdentry))
+	for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next)
+		if (is_subdir(dentry, exp->ex_dentry))
 			break;
-	} while ((xdentry = xdentry->d_parent));
-	exp = NULL;
-out:
 	return exp;
 }
 
@@ -169,30 +129,15 @@
 exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry)
 {
 	svc_export      *exp;
-	struct dentry	*xdentry = dentry;
-	struct dentry	*ndentry = NULL;
 
-	if (clp == NULL || dentry == NULL)
+	if (clp == NULL)
 		return NULL;
 
-	exp = clp->cl_export[EXPORT_HASH(dev)];
-	if (exp)
-		do {
-			ndentry = exp->ex_dentry;
-			if (ndentry)
-				while ((ndentry = ndentry->d_parent)) {
-					if (ndentry == xdentry) {
-#ifdef NFSD_PARANOIA
-dprintk("nfsd: exp_child mount under submount.\n");
-#endif
-						goto out;
-					}
-					if (IS_ROOT(ndentry))
-						break;
-				}
-		} while (NULL != (exp = exp->ex_next));
-	exp = NULL;
-out:
+	for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next) {
+		struct dentry	*ndentry = exp->ex_dentry;
+		if (ndentry && is_subdir(ndentry->d_parent, dentry))
+			break;
+	}
 	return exp;
 }
 
@@ -279,10 +224,8 @@
 	}
 	/* Is this is a sub-export, must be a proper subset of FS */
 	if ((parent = exp_parent(clp, dev, dentry)) != NULL) {
-		if (dev == parent->ex_dev) {
-			dprintk("exp_export: sub-export not valid (Rule 2).\n");
-			goto finish;
-		}
+		dprintk("exp_export: sub-export not valid (Rule 2).\n");
+		goto finish;
 	}
 
 	err = -ENOMEM;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c
--- v2.3.99-pre5/linux/fs/nfsd/nfs3xdr.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfsd/nfs3xdr.c	Fri Apr 21 13:36:39 2000
@@ -731,7 +731,7 @@
 				dchild = dchild->d_parent;
 			dchild = dget(dchild);
 		} else
-			dchild = lookup_one(name, dget(dparent));
+			dchild = lookup_one(name, dparent);
 		if (IS_ERR(dchild))
 			goto noexec;
 		if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode)
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.3.99-pre5/linux/fs/nfsd/nfsproc.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/nfsd/nfsproc.c	Fri Apr 21 13:36:40 2000
@@ -222,7 +222,7 @@
 	if (isdotent(argp->name, argp->len))
 		goto done;
 	fh_lock(dirfhp);
-	dchild = lookup_one(argp->name, dget(dirfhp->fh_dentry));
+	dchild = lookup_one(argp->name, dirfhp->fh_dentry);
 	if (IS_ERR(dchild)) {
 		nfserr = nfserrno(PTR_ERR(dchild));
 		goto out_unlock;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.99-pre5/linux/fs/nfsd/vfs.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/nfsd/vfs.c	Fri Apr 21 13:36:40 2000
@@ -139,7 +139,8 @@
 	} else {
 		nd.mnt = NULL;
 		nd.dentry = dget(dparent);
-		err = walk_name(name, 0, &nd);
+		nd.flags = 0;
+		err = walk_name(name, &nd);
 		if (err)
 			goto out_nfserr;
 		/*
@@ -838,7 +839,7 @@
 	if (!resfhp->fh_dverified) {
 		/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
 		fh_lock(fhp);
-		dchild = lookup_one(fname, dget(dentry));
+		dchild = lookup_one(fname, dentry);
 		err = PTR_ERR(dchild);
 		if (IS_ERR(dchild))
 			goto out_nfserr;
@@ -961,7 +962,7 @@
 	/*
 	 * Compose the response file handle.
 	 */
-	dchild = lookup_one(fname, dget(dentry));
+	dchild = lookup_one(fname, dentry);
 	err = PTR_ERR(dchild);
 	if(IS_ERR(dchild))
 		goto out_nfserr;
@@ -1108,7 +1109,7 @@
 		goto out;
 	fh_lock(fhp);
 	dentry = fhp->fh_dentry;
-	dnew = lookup_one(fname, dget(dentry));
+	dnew = lookup_one(fname, dentry);
 	err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
 		goto out_nfserr;
@@ -1173,7 +1174,7 @@
 	ddir = ffhp->fh_dentry;
 	dirp = ddir->d_inode;
 
-	dnew = lookup_one(fname, dget(ddir));
+	dnew = lookup_one(fname, ddir);
 	err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
 		goto out_nfserr;
@@ -1238,7 +1239,7 @@
 		goto out;
 
 	double_down(&tdir->i_sem, &fdir->i_sem);
-	odentry = lookup_one(fname, dget(fdentry));
+	odentry = lookup_one(fname, fdentry);
 	err = PTR_ERR(odentry);
 	if (IS_ERR(odentry))
 		goto out_nfserr;
@@ -1247,7 +1248,7 @@
 	if (!odentry->d_inode)
 		goto out_dput_old;
 
-	ndentry = lookup_one(tname, dget(tdentry));
+	ndentry = lookup_one(tname, tdentry);
 	err = PTR_ERR(ndentry);
 	if (IS_ERR(ndentry))
 		goto out_dput_old;
@@ -1310,7 +1311,7 @@
 	dentry = fhp->fh_dentry;
 	dirp = dentry->d_inode;
 
-	rdentry = lookup_one(fname, dget(dentry));
+	rdentry = lookup_one(fname, dentry);
 	err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.3.99-pre5/linux/fs/ntfs/fs.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/ntfs/fs.c	Tue Apr 25 17:28:56 2000
@@ -587,7 +587,7 @@
 #endif
 };
 
-static int ntfs_writepage(struct dentry *dentry, struct page *page)
+static int ntfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,ntfs_get_block);
 }
@@ -607,6 +607,7 @@
 struct address_space_operations ntfs_aops = {
 	readpage: ntfs_readpage,
 	writepage: ntfs_writepage,
+	sync_page: block_sync_page,
 	prepare_write: ntfs_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: _ntfs_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/open.c linux/fs/open.c
--- v2.3.99-pre5/linux/fs/open.c	Tue Apr 11 15:09:22 2000
+++ linux/fs/open.c	Mon Apr 24 16:10:27 2000
@@ -327,12 +327,10 @@
 	return res;
 }
 
-/* MOUNT_REWRITE: pass &mnt to lookup_dentry */
 asmlinkage long sys_chdir(const char * filename)
 {
 	int error;
-	struct dentry *dentry, *tmp;
-	struct vfsmount *mnt = NULL, *tmp_mnt;
+	struct nameidata nd;
 	char *name;
 
 	lock_kernel();
@@ -342,27 +340,22 @@
 	if (IS_ERR(name))
 		goto out;
 
-	dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY);
+	error = 0;
+	if (walk_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd))
+		error = walk_name(name, &nd);
 	putname(name);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	if (error)
 		goto out;
 
-	error = permission(dentry->d_inode,MAY_EXEC);
+	error = permission(nd.dentry->d_inode,MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
-	/* exchange dentries */
-	tmp = current->fs->pwd;
-	tmp_mnt = current->fs->pwdmnt;
-	current->fs->pwd = dentry;
-	current->fs->pwdmnt = mnt;
-	dentry = tmp;
-	mnt = tmp_mnt;
+	set_fs_pwd(current->fs, nd.mnt, nd.dentry);
 
 dput_and_out:
-	mntput(mnt);
-	dput(dentry);
+	dput(nd.dentry);
+	mntput(nd.mnt);
 out:
 	unlock_kernel();
 	return error;
@@ -391,14 +384,8 @@
 
 	lock_kernel();
 	error = permission(inode, MAY_EXEC);
-	if (!error) {
-		struct dentry *tmp = current->fs->pwd;
-		struct vfsmount *tmp_mnt = current->fs->pwdmnt;
-		current->fs->pwd = dget(dentry);
-		current->fs->pwdmnt = mntget(mnt);
-		mntput(tmp_mnt);
-		dput(tmp);
-	}
+	if (!error)
+		set_fs_pwd(current->fs, mnt, dentry);
 	unlock_kernel();
 out_putf:
 	fput(file);
@@ -406,12 +393,10 @@
 	return error;
 }
 
-/* MOUNT_REWRITE: pass &mnt to lookup_dentry */
 asmlinkage long sys_chroot(const char * filename)
 {
 	int error;
-	struct dentry *dentry, *tmp;
-	struct vfsmount *mnt = NULL, *tmp_mnt;
+	struct nameidata nd;
 	char *name;
 
 	lock_kernel();
@@ -421,13 +406,14 @@
 	if (IS_ERR(name))
 		goto out;
 
-	dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY);
+	walk_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
+		      LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
+	error = walk_name(name, &nd);	
 	putname(name);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	if (error)
 		goto out;
 
-	error = permission(dentry->d_inode,MAY_EXEC);
+	error = permission(nd.dentry->d_inode,MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
@@ -435,18 +421,12 @@
 	if (!capable(CAP_SYS_CHROOT))
 		goto dput_and_out;
 
-	/* exchange dentries */
-	tmp = current->fs->root;
-	tmp_mnt = current->fs->rootmnt;
-	current->fs->root = dentry;
-	current->fs->rootmnt = mnt;
-	dentry = tmp;
-	mnt = tmp_mnt;
+	set_fs_root(current->fs, nd.mnt, nd.dentry);
+	set_fs_altroot();
 	error = 0;
-
 dput_and_out:
-	mntput(mnt);
-	dput(dentry);
+	dput(nd.dentry);
+	mntput(nd.mnt);
 out:
 	unlock_kernel();
 	return error;
@@ -776,13 +756,20 @@
 	return error;
 }
 
+inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
+{
+	FD_CLR(fd, files->open_fds);
+	if (fd < files->next_fd)
+		files->next_fd = fd;
+}
+
 inline void put_unused_fd(unsigned int fd)
 {
-	write_lock(&current->files->file_lock);
-	FD_CLR(fd, current->files->open_fds);
-	if (fd < current->files->next_fd)
-		current->files->next_fd = fd;
-	write_unlock(&current->files->file_lock);
+	struct files_struct *files = current->files;
+
+	write_lock(&files->file_lock);
+	__put_unused_fd(files, fd);
+	write_unlock(&files->file_lock);
 }
 
 asmlinkage long sys_open(const char * filename, int flags, int mode)
@@ -868,13 +855,13 @@
 
 	error = -EBADF;
 	write_lock(&files->file_lock);
-	filp = frip(fd);
+	filp = frip(files, fd);
 	if (!filp)
 		goto out_unlock;
 	FD_CLR(fd, files->close_on_exec);
-	write_unlock(&files->file_lock);
 	if (release)
-		put_unused_fd(fd);
+		__put_unused_fd(files, fd);
+	write_unlock(&files->file_lock);
 	lock_kernel();
 	error = filp_close(filp, files);
 	unlock_kernel();
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/partitions/Config.in linux/fs/partitions/Config.in
--- v2.3.99-pre5/linux/fs/partitions/Config.in	Tue Apr 11 15:09:22 2000
+++ linux/fs/partitions/Config.in	Wed Apr 12 09:47:30 2000
@@ -14,6 +14,9 @@
    bool '  Alpha OSF partition support' CONFIG_OSF_PARTITION
    bool '  Amiga partition table support' CONFIG_AMIGA_PARTITION
    bool '  Atari partition table support' CONFIG_ATARI_PARTITION
+   if [ "$CONFIG_ARCH_S390" = "y" ]; then
+      bool '  IBM disk label and partition support' CONFIG_IBM_PARTITION
+   fi
    bool '  Macintosh partition map support' CONFIG_MAC_PARTITION
    bool '  PC BIOS (MSDOS partition tables) support' CONFIG_MSDOS_PARTITION
    if [ "$CONFIG_MSDOS_PARTITION" = "y" ]; then
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/partitions/Makefile linux/fs/partitions/Makefile
--- v2.3.99-pre5/linux/fs/partitions/Makefile	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/Makefile	Wed Apr 12 09:47:30 2000
@@ -22,6 +22,10 @@
 O_OBJS += atari.o
 endif
 
+ifeq ($(CONFIG_IBM_PARTITION),y)
+O_OBJS += ibm.o
+endif
+
 ifeq ($(CONFIG_MAC_PARTITION),y)
 O_OBJS += mac.o
 endif
@@ -45,5 +49,6 @@
 ifeq ($(CONFIG_ULTRIX_PARTITION),y)
 O_OBJS += ultrix.o
 endif
+
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/partitions/acorn.c linux/fs/partitions/acorn.c
--- v2.3.99-pre5/linux/fs/partitions/acorn.c	Sun Mar 19 18:35:31 2000
+++ linux/fs/partitions/acorn.c	Fri Apr 14 09:37:10 2000
@@ -485,9 +485,11 @@
 	if (r == 0)
 		r = adfspart_check_POWERTEC(hd, dev, first_sector, first_part_minor);
 #endif
-	if (r < 0)
-		if (warn_no_part) printk(" unable to read boot sectors / partition sectors\n");
-	else if (r)
+	if (r < 0) {
+		if (warn_no_part)
+			printk(" unable to read boot sectors / partition sectors\n");
+	} else if (r) {
 		printk("\n");
+	}
 	return r;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/partitions/check.c linux/fs/partitions/check.c
--- v2.3.99-pre5/linux/fs/partitions/check.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/partitions/check.c	Wed Apr 12 09:47:30 2000
@@ -30,6 +30,7 @@
 #include "osf.h"
 #include "sgi.h"
 #include "sun.h"
+#include "ibm.h"
 
 extern void device_init(void);
 extern void md_setup_drive(void);
@@ -68,9 +69,17 @@
 #ifdef CONFIG_ULTRIX_PARTITION
 	ultrix_partition,
 #endif
+#ifdef CONFIG_IBM_PARTITION
+	ibm_partition,
+#endif
 	NULL
 };
 
+#if defined CONFIG_BLK_DEV_LVM || defined CONFIG_BLK_DEV_LVM_MODULE
+#include <linux/lvm.h>
+void (*lvm_hd_name_ptr) (char *, int) = NULL;
+#endif
+
 /*
  * disk_name() is used by genhd.c and blkpg.c.
  * It formats the devicename of the indicated disk into
@@ -97,6 +106,13 @@
 	 * This requires special handling here.
 	 */
 	switch (hd->major) {
+#if defined CONFIG_BLK_DEV_LVM || defined CONFIG_BLK_DEV_LVM_MODULE
+		case LVM_BLK_MAJOR:
+			*buf = 0;
+			if ( lvm_hd_name_ptr != NULL)
+				(lvm_hd_name_ptr) ( buf, minor);
+			return buf;
+#endif
 		case IDE9_MAJOR:
 			unit += 2;
 		case IDE8_MAJOR:
@@ -387,7 +403,7 @@
 {
 	if (!gdev)
 		return;
-	grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
+		grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
 }
 
 void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size)
@@ -432,10 +448,6 @@
 #ifdef CONFIG_BLK_DEV_MD
 	autodetect_raid();
 #endif
-#ifdef CONFIG_MD_BOOT
-	md_setup_drive();
-#endif
-
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- v2.3.99-pre5/linux/fs/partitions/ibm.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/partitions/ibm.c	Wed Apr 12 09:47:30 2000
@@ -0,0 +1,122 @@
+/*
+ * File...........: linux/fs/partitions/ibm.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#include <asm/ebcdic.h>
+#include "../../drivers/s390/block/dasd_types.h"
+
+typedef enum {
+  ibm_partition_none = 0,
+  ibm_partition_lnx1 = 1,
+  ibm_partition_vol1 = 3,
+  ibm_partition_cms1 = 4
+} ibm_partition_t;
+
+static ibm_partition_t
+get_partition_type ( char * type )
+{
+  static char lnx[5]="LNX1";
+  static char vol[5]="VOL1";
+  static char cms[5]="CMS1";
+  if ( ! strncmp ( lnx, "LNX1",4 ) ) {
+    ASCEBC(lnx,4);
+    ASCEBC(vol,4);
+    ASCEBC(cms,4);
+  }
+  if ( ! strncmp (type,lnx,4) || 
+       ! strncmp (type,"LNX1",4) )
+    return ibm_partition_lnx1;
+  if ( ! strncmp (type,vol,4) )
+    return ibm_partition_vol1;
+  if ( ! strncmp (type,cms,4) )
+    return ibm_partition_cms1;
+  return ibm_partition_none;
+}
+
+void
+ibm_partition (struct gendisk *hd, kdev_t dev)
+{
+	struct buffer_head *bh;
+	ibm_partition_t partition_type;
+	int di = MINOR(dev) >> PARTN_BITS;
+	char type[5] = {0,};
+	char name[7] = {0,};
+	if ( bh = bread( dev, 
+			 dasd_info[di]->sizes.label_block, 
+			 get_ptable_blocksize(dev) ) ) {
+		strncpy ( type,bh -> b_data, 4);
+		strncpy ( name,bh -> b_data + 4, 6);
+        } else {
+		return;
+	}
+	if ( (*(char *)bh -> b_data) & 0x80 ) {
+		EBCASC(name,6);
+	}
+	switch ( partition_type = get_partition_type(type) ) {
+	case ibm_partition_lnx1:
+		printk ( "(LNX1)/%6s:",name);
+		add_gd_partition( hd, MINOR(dev) + 1, 
+				  (dasd_info [di]->sizes.label_block + 1) <<
+				  dasd_info [di]->sizes.s2b_shift,
+				  (dasd_info [di]->sizes.blocks -
+				   dasd_info [di]->sizes.label_block - 1) <<
+				  dasd_info [di]->sizes.s2b_shift );
+		break;
+	case ibm_partition_vol1:
+		printk ( "(VOL1)/%6s:",name);
+		break;
+	case ibm_partition_cms1:
+		printk ( "(CMS1)/%6s:",name);
+		if (* (((long *)bh->b_data) + 13) == 0) {
+		  /* disk holds a CMS filesystem */
+		  add_gd_partition( hd, MINOR(dev) + 1, 
+				    (dasd_info [di]->sizes.label_block + 1) <<
+				    dasd_info [di]->sizes.s2b_shift,
+				    (dasd_info [di]->sizes.blocks -
+				     dasd_info [di]->sizes.label_block) <<
+				    dasd_info [di]->sizes.s2b_shift );
+		  printk ("(CMS)");
+		} else {
+		  /* disk is reserved minidisk */
+		  int offset = (*(((long *)bh->b_data) + 13));
+		  int size = (*(((long *)bh->b_data) + 7)) - 1 - 
+		    (*(((long *)bh->b_data) + 13)) *
+		    ((*(((long *)bh->b_data) + 3)) >> 9);
+		  add_gd_partition( hd, MINOR(dev) + 1, 
+				    offset << dasd_info [di]->sizes.s2b_shift,
+				    size << dasd_info [di]->sizes.s2b_shift );
+		  printk ("(MDSK)");
+		}
+		break;
+	case ibm_partition_none:
+		printk ( "(nonl)/      :");
+/*
+		printk ( "%d %d %d ", MINOR(dev) + 1, 
+			 (dasd_info [di]->sizes.label_block + 1) <<
+			 dasd_info [di]->sizes.s2b_shift,
+			 (dasd_info [di]->sizes.blocks -
+			  dasd_info [di]->sizes.label_block - 1) <<
+			 dasd_info [di]->sizes.s2b_shift );
+*/
+		add_gd_partition( hd, MINOR(dev) + 1, 
+				  (dasd_info [di]->sizes.label_block + 1) <<
+				  dasd_info [di]->sizes.s2b_shift,
+				  (dasd_info [di]->sizes.blocks -
+				   dasd_info [di]->sizes.label_block - 1) <<
+				  dasd_info [di]->sizes.s2b_shift );
+		break;
+	}
+	printk ( "\n" );
+	bforget(bh);
+}
+
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/partitions/ibm.h linux/fs/partitions/ibm.h
--- v2.3.99-pre5/linux/fs/partitions/ibm.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/partitions/ibm.h	Wed Apr 12 09:47:30 2000
@@ -0,0 +1 @@
+void ibm_partition (struct gendisk *hd, kdev_t dev);
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- v2.3.99-pre5/linux/fs/partitions/msdos.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/partitions/msdos.c	Thu Apr 13 22:54:26 2000
@@ -27,9 +27,9 @@
 #include <linux/string.h>
 #include <linux/blk.h>
 
-#ifdef CONFIG_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
 #include <linux/ide.h>	/* IDE xlate */
-#endif /* CONFIG_IDE */
+#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */
 
 #include <asm/system.h>
 
@@ -350,19 +350,19 @@
 	unsigned char *data;
 	int mask = (1 << hd->minor_shift) - 1;
 	int sector_size = get_hardsect_size(dev) / 512;
-#ifdef CONFIG_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
 	int tested_for_xlate = 0;
 
 read_mbr:
-#endif /* CONFIG_IDE */
+#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */
 	if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
 		if (warn_no_part) printk(" unable to read partition table\n");
 		return -1;
 	}
 	data = bh->b_data;
-#ifdef CONFIG_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
 check_table:
-#endif /* CONFIG_IDE */
+#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */
 	/* Use bforget(), because we may have changed the disk geometry */
 	if (*(unsigned short *)  (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
 		bforget(bh);
@@ -370,7 +370,7 @@
 	}
 	p = (struct partition *) (0x1be + data);
 
-#ifdef CONFIG_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
 	if (!tested_for_xlate++) {	/* Do this only once per disk */
 		/*
 		 * Look for various forms of IDE disk geometry translation
@@ -426,7 +426,7 @@
 			(void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
 		}
 	}
-#endif /* CONFIG_IDE */
+#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */
 
 	/* Look for partitions in two passes:
 	   First find the primary partitions, and the DOS-type extended partitions.
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/pipe.c linux/fs/pipe.c
--- v2.3.99-pre5/linux/fs/pipe.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/pipe.c	Fri Apr 21 13:10:14 2000
@@ -274,6 +274,7 @@
 	}
 }
 
+/* No kernel lock held - fine */
 static unsigned int
 pipe_poll(struct file *filp, poll_table *wait)
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.99-pre5/linux/fs/proc/array.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/proc/array.c	Fri Apr 21 16:08:45 2000
@@ -52,6 +52,7 @@
  *			 :  base.c too.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -269,6 +270,9 @@
 {
 	char * orig = buffer;
 	struct mm_struct *mm = task->mm;
+#if defined(CONFIG_ARCH_S390)
+	int line,len;
+#endif
 
 	buffer = task_name(task, buffer);
 	buffer = task_state(task, buffer);
@@ -276,6 +280,10 @@
 		buffer = task_mem(mm, buffer);
 	buffer = task_sig(task, buffer);
 	buffer = task_cap(task, buffer);
+#if defined(CONFIG_ARCH_S390)
+	for(line=0;(len=sprintf_regs(line,buffer,task,NULL,NULL))!=0;line++)
+		buffer+=len;
+#endif
 	return buffer - orig;
 }
 
@@ -637,7 +645,7 @@
 	return retval;
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 int proc_pid_cpu(struct task_struct *task, char * buffer)
 {
 	int i, len;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.3.99-pre5/linux/fs/proc/base.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/proc/base.c	Fri Apr 21 16:08:45 2000
@@ -15,6 +15,7 @@
 
 #include <asm/uaccess.h>
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -474,7 +475,7 @@
   E(PROC_PID_CMDLINE,	"cmdline",	S_IFREG|S_IRUGO),
   E(PROC_PID_STAT,	"stat",		S_IFREG|S_IRUGO),
   E(PROC_PID_STATM,	"statm",	S_IFREG|S_IRUGO),
-#ifdef __SMP__
+#ifdef CONFIG_SMP
   E(PROC_PID_CPU,	"cpu",		S_IFREG|S_IRUGO),
 #endif
   E(PROC_PID_MAPS,	"maps",		S_IFREG|S_IRUGO),
@@ -800,7 +801,7 @@
 		case PROC_PID_MAPS:
 			inode->i_fop = &proc_maps_operations;
 			break;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		case PROC_PID_CPU:
 			inode->i_fop = &proc_info_file_operations;
 			inode->u.proc_i.op.proc_read = proc_pid_cpu;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.3.99-pre5/linux/fs/proc/proc_misc.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/proc/proc_misc.c	Fri Apr 21 16:08:45 2000
@@ -30,6 +30,7 @@
 #include <linux/signal.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -284,14 +285,16 @@
 				 int count, int *eof, void *data)
 {
 	int i, len;
-	unsigned sum = 0;
 	extern unsigned long total_forks;
 	unsigned long jif = jiffies;
+#if !defined(CONFIG_ARCH_S390)
+	unsigned sum = 0;
 
 	for (i = 0 ; i < NR_IRQS ; i++)
 		sum += kstat_irqs(i);
+#endif
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	len = sprintf(page,
 		"cpu  %u %u %u %lu\n",
 		kstat.cpu_user,
@@ -314,9 +317,13 @@
 		"disk_rblk %u %u %u %u\n"
 		"disk_wblk %u %u %u %u\n"
 		"page %u %u\n"
-		"swap %u %u\n"
+#if !defined(CONFIG_ARCH_S390)
+                "swap %u %u\n"
 		"intr %u",
 #else
+                "swap %u %u\n",
+#endif
+#else
 	len = sprintf(page,
 		"cpu  %u %u %u %lu\n"
 		"disk %u %u %u %u\n"
@@ -325,8 +332,12 @@
 		"disk_rblk %u %u %u %u\n"
 		"disk_wblk %u %u %u %u\n"
 		"page %u %u\n"
-		"swap %u %u\n"
+#if !defined(CONFIG_ARCH_S390)
+                "swap %u %u\n"
 		"intr %u",
+#else
+                "swap %u %u\n",
+#endif
 		kstat.cpu_user,
 		kstat.cpu_nice,
 		kstat.cpu_system,
@@ -345,10 +356,14 @@
 		kstat.pgpgin,
 		kstat.pgpgout,
 		kstat.pswpin,
+#if !defined(CONFIG_ARCH_S390)
 		kstat.pswpout,
 		sum);
-	for (i = 0 ; i < NR_IRQS ; i++)
-		len += sprintf(page + len, " %u", kstat_irqs(i));
+        for (i = 0 ; i < NR_IRQS ; i++)
+                len += sprintf(page + len, " %u", kstat_irqs(i));
+#else
+                kstat.pswpout);
+#endif
 	len += sprintf(page + len,
 		"\nctxt %u\n"
 		"btime %lu\n"
@@ -388,6 +403,7 @@
 	return len;
 }
 
+#if !defined(CONFIG_ARCH_S390)
 static int interrupts_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
@@ -399,6 +415,7 @@
 	if (len<0) len = 0;
 	return len;
 }
+#endif
 
 static int filesystems_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -469,7 +486,10 @@
 static int locks_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
-	int len = get_locks_status(page, start, off, count);
+	int len;
+	lock_kernel();
+	len = get_locks_status(page, start, off, count);
+	unlock_kernel();
 	if (len < count) *eof = 1;
 	return len;
 }
@@ -574,7 +594,7 @@
 static ssize_t write_profile(struct file * file, const char * buf,
 			     size_t count, loff_t *ppos)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	extern int setup_profiling_timer (unsigned int multiplier);
 
 	if (count==sizeof(int)) {
@@ -627,7 +647,9 @@
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
 		{"partitions",	partitions_read_proc},
+#if !defined(CONFIG_ARCH_S390)
 		{"interrupts",	interrupts_read_proc},
+#endif
 		{"filesystems",	filesystems_read_proc},
 		{"dma",		dma_read_proc},
 		{"ioports",	ioports_read_proc},
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/proc/proc_tty.c linux/fs/proc/proc_tty.c
--- v2.3.99-pre5/linux/fs/proc/proc_tty.c	Tue Dec  7 09:32:48 1999
+++ linux/fs/proc/proc_tty.c	Fri Apr 21 15:17:57 2000
@@ -93,7 +93,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -123,7 +123,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.3.99-pre5/linux/fs/qnx4/inode.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/qnx4/inode.c	Tue Apr 25 17:28:56 2000
@@ -410,7 +410,7 @@
 	return;
 }
 
-static int qnx4_writepage(struct dentry *dentry, struct page *page)
+static int qnx4_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,qnx4_get_block);
 }
@@ -430,6 +430,7 @@
 struct address_space_operations qnx4_aops = {
 	readpage: qnx4_readpage,
 	writepage: qnx4_writepage,
+	sync_page: block_sync_page,
 	prepare_write: qnx4_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: qnx4_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- v2.3.99-pre5/linux/fs/qnx4/namei.c	Fri Mar 10 16:40:48 2000
+++ linux/fs/qnx4/namei.c	Mon Apr 24 18:56:33 2000
@@ -171,10 +171,6 @@
 		goto end_rmdir;
 	}
 #endif
-	if (!d_unhashed(dentry)) {
-		retval = -EBUSY;
-		goto end_rmdir;
-	}
 	if (inode->i_nlink != 2) {
 		QNX4DEBUG(("empty directory has nlink!=2 (%d)\n", inode->i_nlink));
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/ramfs/inode.c linux/fs/ramfs/inode.c
--- v2.3.99-pre5/linux/fs/ramfs/inode.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/ramfs/inode.c	Tue Apr 25 17:28:56 2000
@@ -76,7 +76,7 @@
  * Writing: just make sure the page gets marked dirty, so that
  * the page stealer won't grab it.
  */
-static int ramfs_writepage(struct dentry * dentry, struct page *page)
+static int ramfs_writepage(struct file *file, struct dentry * dentry, struct page *page)
 {
 	SetPageDirty(page);
 	return 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/readdir.c linux/fs/readdir.c
--- v2.3.99-pre5/linux/fs/readdir.c	Tue Mar  7 14:32:26 2000
+++ linux/fs/readdir.c	Mon Apr 24 18:56:33 2000
@@ -22,7 +22,11 @@
 	if (!file->f_op || !file->f_op->readdir)
 		goto out;
 	down(&inode->i_sem);
-	res = file->f_op->readdir(file, buf, filler);
+	down(&inode->i_zombie);
+	res = -ENOENT;
+	if (!IS_DEADDIR(inode))
+		res = file->f_op->readdir(file, buf, filler);
+	up(&inode->i_zombie);
 	up(&inode->i_sem);
 out:
 	return res;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.3.99-pre5/linux/fs/romfs/inode.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/romfs/inode.c	Sat Apr 15 22:43:09 2000
@@ -506,7 +506,8 @@
 			break;
 		case 3:
 			i->i_op = &page_symlink_inode_operations;
-			i->i_mode = S_IRWXUGO;
+			i->i_data.a_ops = &romfs_aops;
+			i->i_mode = ino | S_IRWXUGO;
 			break;
 		default:
 			/* depending on MBZ for sock/fifos */
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/select.c linux/fs/select.c
--- v2.3.99-pre5/linux/fs/select.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/select.c	Fri Apr 21 12:53:45 2000
@@ -194,7 +194,6 @@
 	retval = 0;
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		lock_kernel();
 		for (i = 0 ; i < n; i++) {
 			unsigned long bit = BIT(i);
 			unsigned long mask;
@@ -227,7 +226,6 @@
 				wait = NULL;
 			}
 		}
-		unlock_kernel();
 		wait = NULL;
 		if (retval || !__timeout || signal_pending(current))
 			break;
@@ -462,9 +460,7 @@
 			goto out_fds1;
 	}
 
-	lock_kernel();
 	fdcount = do_poll(nfds, nchunks, nleft, fds, wait, timeout);
-	unlock_kernel();
 
 	/* OK, now copy the revents fields back to user space. */
 	for(i=0; i < nchunks; i++)
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.3.99-pre5/linux/fs/smbfs/file.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/smbfs/file.c	Tue Apr 25 17:28:56 2000
@@ -167,7 +167,7 @@
  * We are called with the page locked and the caller unlocks.
  */
 static int
-smb_writepage(struct dentry *dentry, struct page *page)
+smb_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	struct inode *inode = dentry->d_inode;
 	unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/stat.c linux/fs/stat.c
--- v2.3.99-pre5/linux/fs/stat.c	Thu Feb 10 17:11:19 2000
+++ linux/fs/stat.c	Thu Apr 13 17:06:05 2000
@@ -25,7 +25,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -115,7 +115,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
@@ -161,7 +161,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -209,7 +209,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/super.c linux/fs/super.c
--- v2.3.99-pre5/linux/fs/super.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/super.c	Wed Apr 26 09:08:09 2000
@@ -76,6 +76,13 @@
 static struct file_system_type *file_systems = NULL;
 static spinlock_t file_systems_lock = SPIN_LOCK_UNLOCKED;
 
+/* WARNING: This can be used only if we _already_ own a reference */
+static void get_filesystem(struct file_system_type *fs)
+{
+	if (fs->owner)
+		__MOD_INC_USE_COUNT(fs->owner);
+}
+
 static void put_filesystem(struct file_system_type *fs)
 {
 	if (fs->owner)
@@ -96,10 +103,10 @@
  *	@fs: the file system structure
  *
  *	Adds the file system passed to the list of file systems the kernel
- *	is aware of for by mount and other syscalls. Returns 0 on success,
+ *	is aware of for mount and other syscalls. Returns 0 on success,
  *	or a negative errno code on an error.
  *
- *	The file_system_type that is passed is linked into the kernel 
+ *	The &struct file_system_type that is passed is linked into the kernel 
  *	structures and must not be freed until the file system has been
  *	unregistered.
  */
@@ -131,8 +138,8 @@
  *	with the kernel. An error is returned if the file system is not found.
  *	Zero is returned on a success.
  *	
- *	Once this function has returned the file_system_type structure may be
- *	freed or reused.
+ *	Once this function has returned the &struct file_system_type structure
+ *	may be freed or reused.
  */
  
 int unregister_filesystem(struct file_system_type * fs)
@@ -269,79 +276,58 @@
 	return fs;
 }
 
-struct vfsmount *vfsmntlist = NULL;
-static struct vfsmount *vfsmnttail = NULL, *mru_vfsmnt = NULL;
+static LIST_HEAD(vfsmntlist);
 
 static struct vfsmount *add_vfsmnt(struct super_block *sb,
 			const char *dev_name, const char *dir_name)
 {
-	struct vfsmount *lptr;
+	struct vfsmount *mnt;
 	char *name;
 
-	lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
-	if (!lptr)
+	mnt = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
+	if (!mnt)
 		goto out;
-	memset(lptr, 0, sizeof(struct vfsmount));
+	memset(mnt, 0, sizeof(struct vfsmount));
 
-	lptr->mnt_sb = sb;
-	lptr->mnt_dev = sb->s_dev;
+	mnt->mnt_sb = sb;
+	mnt->mnt_dev = sb->s_dev;
 
 	/* N.B. Is it really OK to have a vfsmount without names? */
 	if (dev_name) {
 		name = (char *) kmalloc(strlen(dev_name)+1, GFP_KERNEL);
 		if (name) {
 			strcpy(name, dev_name);
-			lptr->mnt_devname = name;
+			mnt->mnt_devname = name;
 		}
 	}
 	if (dir_name) {
 		name = (char *) kmalloc(strlen(dir_name)+1, GFP_KERNEL);
 		if (name) {
 			strcpy(name, dir_name);
-			lptr->mnt_dirname = name;
+			mnt->mnt_dirname = name;
 		}
 	}
 
-	if (vfsmntlist == (struct vfsmount *)NULL) {
-		vfsmntlist = vfsmnttail = lptr;
-	} else {
-		vfsmnttail->mnt_next = lptr;
-		vfsmnttail = lptr;
-	}
+	list_add(&mnt->mnt_list, vfsmntlist.prev);
 out:
-	return lptr;
+	return mnt;
 }
 
 void remove_vfsmnt(kdev_t dev)
 {
-	struct vfsmount *lptr, *tofree;
+	struct list_head *p, *next;
 
-	if (vfsmntlist == NULL)
-		return;
-	lptr = vfsmntlist;
-	if (lptr->mnt_dev == dev) {
-		tofree = lptr;
-		vfsmntlist = lptr->mnt_next;
-		if (vfsmnttail->mnt_dev == dev)
-			vfsmnttail = vfsmntlist;
-	} else {
-		while (lptr->mnt_next != NULL) {
-			if (lptr->mnt_next->mnt_dev == dev)
-				break;
-			lptr = lptr->mnt_next;
-		}
-		tofree = lptr->mnt_next;
-		if (tofree == NULL)
-			return;
-		lptr->mnt_next = lptr->mnt_next->mnt_next;
-		if (vfsmnttail->mnt_dev == dev)
-			vfsmnttail = lptr;
-	}
-	if (tofree == mru_vfsmnt)
-		mru_vfsmnt = NULL;
-	kfree(tofree->mnt_devname);
-	kfree(tofree->mnt_dirname);
-	kfree_s(tofree, sizeof(struct vfsmount));
+	for (p = vfsmntlist.next; p != &vfsmntlist; p = next) {
+		struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list);
+
+		next = p->next;
+		if (mnt->mnt_dev != dev)
+			continue;
+		list_del(&mnt->mnt_list);
+		kfree(mnt->mnt_devname);
+		kfree(mnt->mnt_dirname);
+		kfree(mnt);
+	}
 }
 
 static struct proc_fs_info {
@@ -378,7 +364,7 @@
 
 int get_filesystem_info( char *buf )
 {
-	struct vfsmount *tmp;
+	struct list_head *p;
 	struct proc_fs_info *fs_infop;
 	struct proc_nfs_info *nfs_infop;
 	struct nfs_server *nfss;
@@ -386,7 +372,9 @@
 	char *path,*buffer = (char *) __get_free_page(GFP_KERNEL);
 
 	if (!buffer) return 0;
-	for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160; tmp = tmp->mnt_next) {
+	for (p = vfsmntlist.next; p!=&vfsmntlist && len < PAGE_SIZE - 160;
+	    p = p->next) {
+		struct vfsmount *tmp = list_entry(p, struct vfsmount, mnt_list);
 		if (!tmp->mnt_sb || !tmp->mnt_sb->s_root)
 			continue;
 		path = d_path(tmp->mnt_sb->s_root, tmp, buffer, PAGE_SIZE);
@@ -459,7 +447,7 @@
  *	@sb: superblock to wait on
  *
  *	Waits for a superblock to become unlocked and then returns. It does
- *	not take the lock. This is an internal function. See wait_on_super.
+ *	not take the lock. This is an internal function. See wait_on_super().
  */
  
 void __wait_on_super(struct super_block * sb)
@@ -495,23 +483,20 @@
 			continue;
 		if (!sb->s_dirt)
 			continue;
-		/* N.B. Should lock the superblock while writing */
-		wait_on_super(sb);
-		if (!sb->s_dev || !sb->s_dirt)
-			continue;
-		if (dev && (dev != sb->s_dev))
-			continue;
-		if (sb->s_op && sb->s_op->write_super)
-			sb->s_op->write_super(sb);
+		lock_super(sb);
+		if (sb->s_dev && sb->s_dirt && (!dev || dev == sb->s_dev))
+			if (sb->s_op && sb->s_op->write_super)
+				sb->s_op->write_super(sb);
+		unlock_super(sb);
 	}
 }
 
 /**
  *	get_super	-	get the superblock of a device
- *	@dev: device to get the super block for
+ *	@dev: device to get the superblock for
  *	
  *	Scans the superblock list and finds the superblock of the file system
- *	mounted on the device given. NULL is returned if no match is found.
+ *	mounted on the device given. %NULL is returned if no match is found.
  */
  
 struct super_block * get_super(kdev_t dev)
@@ -561,10 +546,10 @@
 /**
  *	get_empty_super	-	find empty superblocks
  *
- *	Find a super_block with no device assigned. A free superblock is 
+ *	Find a superblock with no device assigned. A free superblock is 
  *	found and returned. If neccessary new superblocks are allocated.
- *	NULL is returned if there are insufficient resources to complete
- *	the request
+ *	%NULL is returned if there are insufficient resources to complete
+ *	the request.
  */
  
 struct super_block *get_empty_super(void)
@@ -659,6 +644,165 @@
 			kdevname(dev));
 }
 
+static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
+	char *dev_name, int flags, void * data)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+	struct block_device *bdev;
+	struct block_device_operations *bdops;
+	struct super_block * sb;
+	kdev_t dev;
+	int error;
+	/* What device it is? */
+	if (!dev_name || !*dev_name)
+		return ERR_PTR(-EINVAL);
+	dentry = lookup_dentry(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
+	if (IS_ERR(dentry))
+		return (struct super_block *)dentry;
+	inode = dentry->d_inode;
+	error = -ENOTBLK;
+	if (!S_ISBLK(inode->i_mode))
+		goto out;
+	error = -EACCES;
+	if (IS_NODEV(inode))
+		goto out;
+	bdev = inode->i_bdev;
+	bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) );
+	if (bdops) bdev->bd_op = bdops;
+	/* Done with lookups, semaphore down */
+	down(&mount_sem);
+	dev = to_kdev_t(bdev->bd_dev);
+	check_disk_change(dev);
+	error = -EACCES;
+	if (!(flags & MS_RDONLY) && is_read_only(dev))
+		goto out;
+	sb = get_super(dev);
+	if (sb) {
+		error = -EBUSY;
+		goto out;
+		/* MOUNT_REWRITE: the following should be used
+		if (fs_type == sb->s_type) {
+			dput(dentry);
+			return sb;
+		}
+		*/
+	} else {
+		mode_t mode = FMODE_READ; /* we always need it ;-) */
+		if (!(flags & MS_RDONLY))
+			mode |= FMODE_WRITE;
+		error = blkdev_get(bdev, mode, 0, BDEV_FS);
+		if (error)
+			goto out;
+		error = -EINVAL;
+		sb = read_super(dev, bdev, fs_type, flags, data, 0);
+		if (sb) {
+			get_filesystem(fs_type);
+			dput(dentry);
+			return sb;
+		}
+		blkdev_put(bdev, BDEV_FS);
+	}
+out:
+	dput(dentry);
+	up(&mount_sem);
+	return ERR_PTR(error);
+}
+
+static struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+	int flags, void * data)
+{
+	kdev_t dev;
+	int error = -EMFILE;
+	down(&mount_sem);
+	dev = get_unnamed_dev();
+	if (dev) {
+		struct super_block * sb;
+		error = -EINVAL;
+		sb = read_super(dev, NULL, fs_type, flags, data, 0);
+		if (sb) {
+			get_filesystem(fs_type);
+			return sb;
+		}
+		put_unnamed_dev(dev);
+	}
+	up(&mount_sem);
+	return ERR_PTR(error);
+}
+
+static struct block_device *kill_super(struct super_block *sb, int umount_root)
+{
+	struct block_device *bdev;
+	kdev_t dev;
+	lock_super(sb);
+	if (sb->s_op) {
+		if (sb->s_op->write_super && sb->s_dirt)
+			sb->s_op->write_super(sb);
+		if (sb->s_op->put_super)
+			sb->s_op->put_super(sb);
+	}
+
+	/* Forget any remaining inodes */
+	if (invalidate_inodes(sb)) {
+		printk("VFS: Busy inodes after unmount. "
+			"Self-destruct in 5 seconds.  Have a nice day...\n");
+	}
+
+	dev = sb->s_dev;
+	sb->s_dev = 0;		/* Free the superblock */
+	bdev = sb->s_bdev;
+	sb->s_bdev = NULL;
+	put_filesystem(sb->s_type);
+	sb->s_type = NULL;
+	unlock_super(sb);
+	if (umount_root) {
+		/* special: the old device driver is going to be
+		   a ramdisk and the point of this call is to free its
+		   protected memory (even if dirty). */
+		destroy_buffers(dev);
+	}
+	if (bdev) {
+		blkdev_put(bdev, BDEV_FS);
+		bdput(bdev);
+	} else
+		put_unnamed_dev(dev);
+	return bdev;
+}
+
+/*
+ * Alters the mount flags of a mounted file system. Only the mount point
+ * is used as a reference - file system type and the device are ignored.
+ */
+
+static int do_remount_sb(struct super_block *sb, int flags, char *data)
+{
+	int retval;
+	
+	if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
+		return -EACCES;
+		/*flags |= MS_RDONLY;*/
+	/* If we are remounting RDONLY, make sure there are no rw files open */
+	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
+		if (!fs_may_remount_ro(sb))
+			return -EBUSY;
+	if (sb->s_op && sb->s_op->remount_fs) {
+		lock_super(sb);
+		retval = sb->s_op->remount_fs(sb, &flags, data);
+		unlock_super(sb);
+		if (retval)
+			return retval;
+	}
+	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+
+	/*
+	 * We can't invalidate inodes as we can loose data when remounting
+	 * (someone might manage to alter data while we are waiting in lock_super()
+	 * or in foo_remount_fs()))
+	 */
+
+	return 0;
+}
+
 static int d_umount(struct super_block * sb)
 {
 	struct dentry * root = sb->s_root;
@@ -747,32 +891,8 @@
 	retval = d_umount(sb);
 	if (retval)
 		goto out;
-
-	if (sb->s_op) {
-		if (sb->s_op->write_super && sb->s_dirt)
-			sb->s_op->write_super(sb);
-	}
-
-	lock_super(sb);
-	if (sb->s_op) {
-		if (sb->s_op->put_super)
-			sb->s_op->put_super(sb);
-	}
-
-	/* Forget any remaining inodes */
-	if (invalidate_inodes(sb)) {
-		printk("VFS: Busy inodes after unmount. "
-			"Self-destruct in 5 seconds.  Have a nice day...\n");
-	}
-
-	sb->s_dev = 0;		/* Free the superblock */
-	bdev = sb->s_bdev;
-	sb->s_bdev = NULL;
-	put_filesystem(sb->s_type);
-	sb->s_type = NULL;
-	unlock_super(sb);
-
 	remove_vfsmnt(dev);
+	bdev = kill_super(sb, unmount_root);
 
 	return bdev;
 
@@ -796,15 +916,8 @@
 	bdev = do_umount(dev, 0, flags);
 	if (IS_ERR(bdev))
 		retval = PTR_ERR(bdev);
-	else {
+	else
 		retval = 0;
-		if (bdev) {
-			blkdev_put(bdev, BDEV_FS);
-			bdput(bdev);
-		} else {
-			put_unnamed_dev(dev);
-		}
-	}
 	up(&mount_sem);
 out:
 	return retval;
@@ -877,170 +990,19 @@
 }
 
 /*
- * do_mount() does the actual mounting after sys_mount has done the ugly
- * parameter parsing. When enough time has gone by, and everything uses the
- * new mount() parameters, sys_mount() can then be cleaned up.
- *
- * We cannot mount a filesystem if it has active, used, or dirty inodes.
- * We also have to flush all inode-data for this device, as the new mount
- * might need new info.
- *
- * [21-Mar-97] T.Schoebel-Theuer: Now this can be overridden when
- * supplying a leading "!" before the dir_name, allowing "stacks" of
- * mounted filesystems. The stacking will only influence any pathname lookups
- * _after_ the mount, but open file descriptors or working directories that
- * are now covered remain valid. For example, when you overmount /home, any
- * process with old cwd /home/joe will continue to use the old versions,
- * as long as relative paths are used, but absolute paths like /home/joe/xxx
- * will go to the new "top of stack" version. In general, crossing a
- * mount point will always go to the top of stack element.
- * Anyone using this new feature must know what he/she is doing.
+ * change filesystem flags. dir should be a physical root of filesystem.
+ * If you've mounted a non-root directory somewhere and want to do remount
+ * on it - tough luck.
  */
 
-static int do_mount(struct block_device *bdev, const char *dev_name,
-	     const char *dir_name, const char * type, int flags, void * data)
-{
-	kdev_t dev;
-	struct dentry * dir_d;
-	struct super_block * sb;
-	struct vfsmount *vfsmnt;
-	struct file_system_type *fs_type;
-	int error;
-
-	if (bdev) {
-		mode_t mode = FMODE_READ; /* we always need it ;-) */
-		if (!(flags & MS_RDONLY))
-			mode |= FMODE_WRITE;
-		dev = to_kdev_t(bdev->bd_dev);
-		error = blkdev_get(bdev, mode, 0, BDEV_FS);
-		if (error)
-			return error;
-	} else {
-		dev = get_unnamed_dev();
-		if (!dev)
-			return -EMFILE;	/* huh? */
-	}
-
-	error = -EACCES;
-	if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
-		goto out;
-
-	/*
-	 * Do the lookup first to force automounting.
-	 */
-	dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-	error = PTR_ERR(dir_d);
-	if (IS_ERR(dir_d))
-		goto out;
-
-	down(&mount_sem);
-	error = -ENOTDIR;
-	if (!S_ISDIR(dir_d->d_inode->i_mode))
-		goto dput_and_out;
-
-	error = -EBUSY;
-	if (dir_d->d_covers != dir_d)
-		goto dput_and_out;
-
-	error = -EINVAL;
-	if (!dev)
-		goto dput_and_out;
-	check_disk_change(dev);
-	sb = get_super(dev);
-	if (sb) {
-		/* Already mounted */
-		error = -EBUSY;
-		goto dput_and_out;
-	}
-
-	fs_type = get_fs_type(type);
-	if (!fs_type) {
-		printk("VFS: on device %s: get_fs_type(%s) failed\n",
-		       kdevname(dev), type);
-		goto dput_and_out;
-	}
-
-	sb = read_super(dev, bdev, fs_type, flags, data, 0);
-	if (!sb)
-		goto fsput_and_out;
-
-	/*
-	 * We may have slept while reading the super block, 
-	 * so we check afterwards whether it's safe to mount.
-	 */
-	error = -EBUSY;
-	if (!fs_may_mount(dev))
-		goto bdput_and_out;
-
-	error = -ENOMEM;
-	vfsmnt = add_vfsmnt(sb, dev_name, dir_name);
-	if (vfsmnt) {
-		d_mount(dget(dir_d), sb->s_root);
-		dput(dir_d);
-		up(&mount_sem);
-		return 0;
-	}
-
-bdput_and_out:
-	/* FIXME: ->put_super() is needed here */
-	sb->s_bdev = NULL;
-	sb->s_dev = 0;
-	sb->s_type = NULL;
-	if (bdev)
-		bdput(bdev);
-fsput_and_out:
-	put_filesystem(fs_type);
-dput_and_out:
-	dput(dir_d);
-	up(&mount_sem);
-out:
-	if (bdev)
-		blkdev_put(bdev, BDEV_FS);
-	else
-		put_unnamed_dev(dev);
-	return error;
-}
-
-
-/*
- * Alters the mount flags of a mounted file system. Only the mount point
- * is used as a reference - file system type and the device are ignored.
- */
-
-static int do_remount_sb(struct super_block *sb, int flags, char *data)
-{
-	int retval;
-	
-	if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
-		return -EACCES;
-		/*flags |= MS_RDONLY;*/
-	/* If we are remounting RDONLY, make sure there are no rw files open */
-	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
-		if (!fs_may_remount_ro(sb))
-			return -EBUSY;
-	if (sb->s_op && sb->s_op->remount_fs) {
-		lock_super(sb);
-		retval = sb->s_op->remount_fs(sb, &flags, data);
-		unlock_super(sb);
-		if (retval)
-			return retval;
-	}
-	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
-
-	/*
-	 * We can't invalidate inodes as we can loose data when remounting
-	 * (someone might manage to alter data while we are waiting in lock_super()
-	 * or in foo_remount_fs()))
-	 */
-
-	return 0;
-}
-
 static int do_remount(const char *dir,int flags,char *data)
 {
 	struct dentry *dentry;
 	int retval;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	dentry = lookup_dentry(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
 	retval = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
@@ -1111,9 +1073,9 @@
 		  unsigned long new_flags, void *data_page)
 {
 	struct file_system_type * fstype;
-	struct dentry * dentry = NULL;
-	struct inode * inode = NULL;
-	struct block_device *bdev = NULL;
+	struct dentry * dir_d;
+	struct vfsmount *mnt;
+	struct super_block *sb;
 	int retval;
 	unsigned long flags = 0;
  
@@ -1126,59 +1088,84 @@
 	if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
 		return -EINVAL;
 
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
+	/* OK, looks good, now let's see what do they want */
 
-	if ((new_flags &
-	     (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
-		retval = do_remount(dir_name,
-				    new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
+	/* just change the flags? - capabilities are checked in do_remount() */
+	if ((new_flags & (MS_MGC_MSK|MS_REMOUNT)) == (MS_MGC_VAL|MS_REMOUNT))
+		return do_remount(dir_name, new_flags&~(MS_MGC_MSK|MS_REMOUNT),
 				    (char *) data_page);
-		goto out;
-	}
 
+	if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
+		flags = new_flags & ~MS_MGC_MSK;
+
+	/* loopback mount? This is special - requires fewer capabilities */
+	/* MOUNT_REWRITE: ... and is yet to be merged */
+
+	/* for the rest we _really_ need capabilities... */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	/* ... filesystem driver... */
 	fstype = get_fs_type(type_page);
-	retval = -ENODEV;
 	if (!fstype)		
-		goto out;
+		return -ENODEV;
 
-	if (fstype->fs_flags & FS_REQUIRES_DEV) {
-		struct block_device_operations *bdops;
+	/* ... and mountpoint. Do the lookup first to force automounting. */
+	dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
+	retval = PTR_ERR(dir_d);
+	if (IS_ERR(dir_d))
+		goto fs_out;
 
-		retval = -EINVAL;
-		if (!dev_name || !*dev_name)
-			goto fs_out;
-		dentry = lookup_dentry(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
-		retval = PTR_ERR(dentry);
-		if (IS_ERR(dentry))
-			goto fs_out;
-
-		inode = dentry->d_inode;
-		retval = -ENOTBLK;
-		if (!S_ISBLK(inode->i_mode))
-			goto dput_and_out;
-
-		retval = -EACCES;
-		if (IS_NODEV(inode))
-			goto dput_and_out;
-
-		bdev = inode->i_bdev;
-		bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) );
-		if (bdops) bdev->bd_op = bdops;
-	}
+	/* get superblock, locks mount_sem on success */
+	if (fstype->fs_flags & FS_REQUIRES_DEV)
+		sb = get_sb_bdev(fstype, dev_name,flags, data_page);
+	else
+		sb = get_sb_nodev(fstype, flags, data_page);
 
-	if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
-		flags = new_flags & ~MS_MGC_MSK;
+	retval = PTR_ERR(sb);
+	if (IS_ERR(sb))
+		goto dput_out;
 
-	retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags,
-				data_page);
+	retval = -ENOENT;
+	if (d_unhashed(dir_d))
+		goto fail;
 
-dput_and_out:
-	dput(dentry);
+	retval = -ENOTDIR;
+	if (!S_ISDIR(dir_d->d_inode->i_mode))
+		goto fail;
+
+	retval = -EBUSY;
+	if (dir_d->d_covers != dir_d)
+		goto fail;
+
+	/*
+	 * We may have slept while reading the super block, 
+	 * so we check afterwards whether it's safe to mount.
+	 */
+	retval = -EBUSY;
+	if (!fs_may_mount(sb->s_dev))
+		goto fail;
+
+	retval = -ENOMEM;
+	mnt = add_vfsmnt(sb, dev_name, dir_name);
+	if (!mnt)
+		goto fail;
+	d_mount(dget(dir_d), sb->s_root);
+
+	retval = 0;
+unlock_out:
+	up(&mount_sem);
+dput_out:
+	dput(dir_d);
 fs_out:
 	put_filesystem(fstype);
-out:
 	return retval;
+
+fail:
+	dput(sb->s_root);
+	sb->s_root = NULL;
+	kill_super(sb, 0);
+	goto unlock_out;
 }
 
 asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
@@ -1242,39 +1229,38 @@
 	int path_start = -1;
 
 #ifdef CONFIG_ROOT_NFS
-	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
-		ROOT_DEV = 0;
-		if ((fs_type = get_fs_type("nfs"))) {
-			sb = get_empty_super(); /* "can't fail" */
-			sb->s_dev = get_unnamed_dev();
-			sb->s_bdev = NULL;
-			sb->s_flags = root_mountflags;
-			sema_init(&sb->s_vfs_rename_sem,1);
-			sema_init(&sb->s_nfsd_free_path_sem,1);
-			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
-			if (vfsmnt) {
-				if (nfs_root_mount(sb) >= 0) {
-					sb->s_dirt = 0;
-					sb->s_type = fs_type;
-					current->fs->root = dget(sb->s_root);
-					current->fs->rootmnt = mntget(vfsmnt);
-					current->fs->pwd = dget(sb->s_root);
-					current->fs->pwdmnt = mntget(vfsmnt);
-					ROOT_DEV = sb->s_dev;
-			                printk (KERN_NOTICE "VFS: Mounted root (NFS filesystem)%s.\n", (sb->s_flags & MS_RDONLY) ? " readonly" : "");
-					return;
-				}
-				remove_vfsmnt(sb->s_dev);
-			}
-			put_unnamed_dev(sb->s_dev);
-			sb->s_dev = 0;
-			put_filesystem(fs_type);
-		}
-		if (!ROOT_DEV) {
-			printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
-			ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
-		}
-	}
+	void *data;
+	if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR)
+		goto skip_nfs;
+	fs_type = get_fs_type("nfs");
+	if (!fs_type)
+		goto no_nfs;
+	ROOT_DEV = get_unnamed_dev();
+	if (!ROOT_DEV)
+		/*
+		 * Your /linuxrc sucks worse than MSExchange - that's the
+		 * only way you could run out of anon devices at that point.
+		 */
+		goto no_anon;
+	data = nfs_root_data();
+	if (!data)
+		goto no_server;
+	sb = read_super(ROOT_DEV, NULL, fs_type, root_mountflags, data, 1);
+	if (sb)
+		/*
+		 * We _can_ fail there, but if that will happen we have no
+		 * chance anyway (no memory for vfsmnt and we _will_ need it,
+		 * no matter which fs we try to mount).
+		 */
+		goto mount_it;
+no_server:
+	put_unnamed_dev(ROOT_DEV);
+no_anon:
+	put_filesystem(fs_type);
+no_nfs:
+	printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
+	ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
+skip_nfs:
 #endif
 
 #ifdef CONFIG_BLK_DEV_FD
@@ -1369,11 +1355,8 @@
 		kdevname(ROOT_DEV));
 
 mount_it:
-	sb->s_flags = root_mountflags;
-	current->fs->root = dget(sb->s_root);
-	current->fs->rootmnt = mntget(vfsmnt);
-	current->fs->pwd = dget(sb->s_root);
-	current->fs->pwdmnt = mntget(vfsmnt);
+	set_fs_root(current->fs, vfsmnt, sb->s_root);
+	set_fs_pwd(current->fs, vfsmnt, sb->s_root);
 	printk ("VFS: Mounted root (%s filesystem)%s.\n",
 		fs_type->name,
 		(sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1388,7 +1371,8 @@
 	}
 	else vfsmnt = add_vfsmnt (sb, "/dev/root", "/");
 	if (vfsmnt) {
-		bdput(bdev); /* sb holds a reference */
+		if (bdev)
+			bdput(bdev); /* sb holds a reference */
 		return;
 	}
 	panic("VFS: add_vfsmnt failed for root fs");
@@ -1402,27 +1386,22 @@
 {
 	struct task_struct *p;
 
+	/* We can't afford dput() blocking under the tasklist_lock */
+	mntget(old_rootmnt);
+	dget(old_root);
+
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (!p->fs) continue;
-		if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) {
-			p->fs->root = dget(new_root);
-			p->fs->rootmnt = mntget(new_rootmnt);
-			mntput(old_rootmnt);
-			dput(old_root);
-			printk(KERN_DEBUG "chroot_fs_refs: changed root of "
-			    "process %d\n",p->pid);
-		}
-		if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt) {
-			p->fs->pwd = dget(new_root);
-			p->fs->pwdmnt = mntget(new_rootmnt);
-			mntput(old_rootmnt);
-			dput(old_root);
-			printk(KERN_DEBUG "chroot_fs_refs: changed cwd of "
-			    "process %d\n",p->pid);
-		}
+		if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt)
+			set_fs_root(p->fs, new_rootmnt, new_root);
+		if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt)
+			set_fs_pwd(p->fs, new_rootmnt, new_root);
 	}
 	read_unlock(&tasklist_lock);
+
+	dput(old_root);
+	mntput(old_rootmnt);
 }
 
 /*
@@ -1570,14 +1549,6 @@
 		bdev = do_umount(old_root_dev,1, 0);
 		if (!IS_ERR(bdev)) {
 			printk("okay\n");
-			/* special: the old device driver is going to be
-			   a ramdisk and the point of this call is to free its
-			   protected memory (even if dirty). */
-			destroy_buffers(old_root_dev);
-			if (bdev) {
-				blkdev_put(bdev, BDEV_FS);
-				bdput(bdev);
-			}
 			return 0;
 		}
 		printk(KERN_ERR "error %ld\n",PTR_ERR(bdev));
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.3.99-pre5/linux/fs/sysv/inode.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/sysv/inode.c	Tue Apr 25 17:28:56 2000
@@ -516,7 +516,6 @@
 /* This is only called on sync() and umount(), when s_dirt=1. */
 static void sysv_write_super(struct super_block *sb)
 {
-	lock_super(sb);
 	if (buffer_dirty(sb->sv_bh1) || buffer_dirty(sb->sv_bh2)) {
 		/* If we are going to write out the super block,
 		   then attach current time stamp.
@@ -534,7 +533,6 @@
 		mark_buffer_dirty(sb->sv_bh2, 1);
 	}
 	sb->s_dirt = 0;
-	unlock_super(sb);
 }
 
 static void sysv_put_super(struct super_block *sb)
@@ -941,7 +939,7 @@
 	return NULL;
 }
 
-static int sysv_writepage(struct dentry *dentry, struct page *page)
+static int sysv_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,sysv_get_block);
 }
@@ -960,6 +958,7 @@
 struct address_space_operations sysv_aops = {
 	readpage: sysv_readpage,
 	writepage: sysv_writepage,
+	sync_page: block_sync_page,
 	prepare_write: sysv_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: sysv_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.3.99-pre5/linux/fs/sysv/namei.c	Fri Mar 10 16:40:48 2000
+++ linux/fs/sysv/namei.c	Mon Apr 24 18:56:33 2000
@@ -389,10 +389,6 @@
 		retval = -ENOTEMPTY;
 		goto end_rmdir;
 	}
-	if (!d_unhashed(dentry)) {
-		retval = -EBUSY;
-		goto end_rmdir;
-	}
 	if (inode->i_nlink != 2)
 		printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink);
 	de->inode = 0;
@@ -552,9 +548,6 @@
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
 		if (new_inode) {
-			retval = -EBUSY;
-			if (!d_unhashed(new_dentry))
-				goto end_rename;
 			retval = -ENOTEMPTY;
 			if (!empty_dir(new_inode))
 				goto end_rename;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.3.99-pre5/linux/fs/udf/file.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/udf/file.c	Tue Apr 25 17:28:56 2000
@@ -65,7 +65,7 @@
 	return 0;
 }
 
-static int udf_adinicb_writepage(struct dentry *dentry, struct page *page)
+static int udf_adinicb_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	struct inode *inode = (struct inode *)page->mapping->host;
 
@@ -118,6 +118,7 @@
 struct address_space_operations udf_adinicb_aops = {
 	readpage:			udf_adinicb_readpage,
 	writepage:			udf_adinicb_writepage,
+	sync_page:		block_sync_page,
 	prepare_write:		udf_adinicb_prepare_write,
 	commit_write:		udf_adinicb_commit_write,
 };
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.3.99-pre5/linux/fs/udf/inode.c	Tue Apr 11 15:09:23 2000
+++ linux/fs/udf/inode.c	Tue Apr 25 17:28:56 2000
@@ -125,7 +125,7 @@
 		udf_trunc(inode);
 }
 
-static int udf_writepage(struct dentry *dentry, struct page *page)
+static int udf_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page, udf_get_block);
 }
@@ -148,6 +148,7 @@
 struct address_space_operations udf_aops = {
 	readpage:			udf_readpage,
 	writepage:			udf_writepage,
+	sync_page:		block_sync_page,
 	prepare_write:		udf_prepare_write,
 	commit_write:		generic_commit_write,
 	bmap:				udf_bmap,
@@ -201,7 +202,7 @@
 	mark_buffer_dirty(bh, 1);
 	udf_release_data(bh);
 
-	inode->i_data.a_ops->writepage(NULL, page);
+	inode->i_data.a_ops->writepage(NULL, NULL, page);
 	UnlockPage(page);
 	page_cache_release(page);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/udf/namei.c linux/fs/udf/namei.c
--- v2.3.99-pre5/linux/fs/udf/namei.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/udf/namei.c	Mon Apr 24 18:56:33 2000
@@ -344,9 +344,6 @@
 	Uint32 extoffset, elen, offset;
 	struct buffer_head *bh = NULL;
 
-	*err = -EINVAL;
-	if (!dir || !dir->i_nlink)
-		return NULL;
 	sb = dir->i_sb;
 
 	if (dentry->d_name.len)
@@ -365,6 +362,7 @@
 	}
 	else if (dir->i_size != 0)
 	{
+		/* WTF??? */
 		*err = -ENOENT;
 		return NULL;
 	}
@@ -724,7 +722,7 @@
 	cfi.fileCharacteristics = FILE_DIRECTORY | FILE_PARENT;
 	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
 	udf_release_data(fibh.sbh);
-	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+	inode->i_mode = S_IFDIR | mode;
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
 	mark_inode_dirty(inode);
@@ -1165,9 +1163,6 @@
 
 		if (new_inode)
 		{
-			retval = -EBUSY;
-			if (!d_unhashed(new_dentry))
-				goto end_rename;
 			retval = -ENOTEMPTY;
 			if (!empty_dir(new_inode))
 				goto end_rename;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.3.99-pre5/linux/fs/ufs/inode.c	Mon Mar 27 08:08:30 2000
+++ linux/fs/ufs/inode.c	Tue Apr 25 17:28:56 2000
@@ -540,7 +540,7 @@
 	return NULL;
 }
 
-static int ufs_writepage(struct dentry *dentry, struct page *page)
+static int ufs_writepage(struct file *file, struct dentry *dentry, struct page *page)
 {
 	return block_write_full_page(page,ufs_getfrag_block);
 }
@@ -559,6 +559,7 @@
 struct address_space_operations ufs_aops = {
 	readpage: ufs_readpage,
 	writepage: ufs_writepage,
+	sync_page: block_sync_page,
 	prepare_write: ufs_prepare_write,
 	commit_write: generic_commit_write,
 	bmap: ufs_bmap
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/ufs/namei.c linux/fs/ufs/namei.c
--- v2.3.99-pre5/linux/fs/ufs/namei.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/ufs/namei.c	Mon Apr 24 18:56:33 2000
@@ -240,8 +240,6 @@
 	
 	*err = -EINVAL;
 	*res_dir = NULL;
-	if (!dir || !dir->i_nlink)
-		return NULL;
 		
 	sb = dir->i_sb;
 	flags = sb->u.ufs_sb.s_flags;
@@ -250,14 +248,6 @@
 
 	if (!namelen)
 		return NULL;
-	/*
-	 * Is this a busy deleted directory?  Can't create new files if so
-	 */
-	if (dir->i_size == 0)
-	{
-		*err = -ENOENT;
-		return NULL;
-	}
 	bh = ufs_bread (dir, 0, 0, err);
 	if (!bh)
 		return NULL;
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.3.99-pre5/linux/fs/umsdos/inode.c	Tue Mar 14 19:10:40 2000
+++ linux/fs/umsdos/inode.c	Fri Apr 21 13:36:40 2000
@@ -389,7 +389,7 @@
 extern kdev_t ROOT_DEV;
 static struct dentry *check_pseudo_root(struct super_block *sb)
 {
-	struct dentry *root, *init;
+	struct dentry *root, *sbin, *init;
 
 	/*
 	 * Check whether we're mounted as the root device.
@@ -398,34 +398,40 @@
 		
 	if (sb->s_dev != ROOT_DEV)
 		goto out_noroot;
-		
-printk("check_pseudo_root: mounted as root\n");
 
-	root = lookup_dentry(UMSDOS_PSDROOT_NAME, dget(sb->s_root), 0); 
+	/* 
+	 * lookup_dentry needs a (so far non-existent) root. 
+	 */
+	printk(KERN_INFO "check_pseudo_root: mounted as root\n");
+	root = lookup_one(UMSDOS_PSDROOT_NAME, sb->s_root); 
 	if (IS_ERR(root))
 		goto out_noroot;
-	if (!root->d_inode)
+	if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))
 		goto out_dput;
-printk("check_pseudo_root: found %s/%s\n",
-root->d_parent->d_name.name, root->d_name.name);
 
-	/* look for /sbin/init */
-	init = lookup_dentry("sbin/init", dget(root), 0);
-	if (!IS_ERR(init)) {
-		if (init->d_inode)
-			goto root_ok;
-		dput(init);
-	}
-	/* check for other files? */
-	goto out_dput;
+	printk(KERN_INFO "check_pseudo_root: found %s/%s\n", root->d_parent->d_name.name, root->d_name.name);
 
-root_ok:
-printk("check_pseudo_root: found %s/%s, enabling pseudo-root\n",
-init->d_parent->d_name.name, init->d_name.name);
+	/* look for /sbin/init */
+	sbin = lookup_one("sbin", root);
+	if (IS_ERR(sbin))
+		goto out_dput;
+	if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode))
+		goto out_dput_sbin;
+	init = lookup_one("init", sbin);
+	if (IS_ERR(init))
+		goto out_dput_sbin;
+	if (!init->d_inode)
+		goto out_dput_init;
+	printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name);
+	dput(sbin);
 	dput(init);
 	return root;
 
 	/* Alternate root not found ... */
+out_dput_init:
+	dput(init);
+out_dput_sbin:
+	dput(sbin);
 out_dput:
 	dput(root);
 out_noroot:
diff -u --recursive --new-file v2.3.99-pre5/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.3.99-pre5/linux/fs/vfat/namei.c	Tue Mar 14 19:10:40 2000
+++ linux/fs/vfat/namei.c	Mon Apr 24 18:56:33 2000
@@ -1080,9 +1080,6 @@
 	struct buffer_head *bh = NULL;
 	struct msdos_dir_entry *de;
 
-	if (!d_unhashed(dentry))
-		return -EBUSY;
-
 	res = fat_dir_empty(dentry->d_inode);
 	if (res)
 		return res;
@@ -1202,9 +1199,6 @@
 		}
 
 		if (is_dir) {
-			res =-EBUSY;
-			if (!d_unhashed(new_dentry))
-				goto rename_done;
 			res = fat_dir_empty(new_inode);
 			if (res)
 				goto rename_done;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-alpha/elf.h linux/include/asm-alpha/elf.h
--- v2.3.99-pre5/linux/include/asm-alpha/elf.h	Wed Jun 24 14:30:11 1998
+++ linux/include/asm-alpha/elf.h	Thu Apr 13 08:11:49 2000
@@ -127,8 +127,7 @@
 
 #ifdef __KERNEL__
 #define SET_PERSONALITY(EX, IBCS2)				\
-	current->personality =					\
-	  ((EX).e_flags & EF_ALPHA_32BIT			\
+	set_personality((EX).e_flags & EF_ALPHA_32BIT		\
 	   ? PER_LINUX_32BIT : (IBCS2) ? PER_SVR4 : PER_LINUX)
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-arc/hardware.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-arc/hardware.h	Tue Apr 25 16:54:37 2000
@@ -43,10 +43,8 @@
  * Screen mapping information
  */
 #define SCREEN_START		0x02000000
-#define SCREEN2_END		0x02078000
-#define SCREEN2_BASE		0x02000000
-#define SCREEN1_END		0x02000000
-#define SCREEN1_BASE		0x01f88000
+#define SCREEN_END		0x02078000
+#define SCREEN_BASE		0x02000000
 
 
 #ifndef __ASSEMBLY__
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-cl7500/hardware.h linux/include/asm-arm/arch-cl7500/hardware.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-cl7500/hardware.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-arm/arch-cl7500/hardware.h	Tue Apr 25 16:54:38 2000
@@ -44,10 +44,8 @@
 
 /* Let's define SCREEN_START for CL7500, even though it's a lie. */
 #define SCREEN_START		0x02000000	/* VRAM */
-#define SCREEN2_END		0xe0000000
-#define SCREEN2_BASE		0xd8000000
-#define SCREEN1_END		0xd8000000
-#define SCREEN1_BASE		0xd0000000
+#define SCREEN_END		0xdfc00000
+#define SCREEN_BASE		0xdf800000
 
 #define FLUSH_BASE		0xdf000000
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-cl7500/vmalloc.h linux/include/asm-arm/arch-cl7500/vmalloc.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-cl7500/vmalloc.h	Tue Apr 11 15:09:23 2000
+++ linux/include/asm-arm/arch-cl7500/vmalloc.h	Tue Apr 25 16:54:38 2000
@@ -13,4 +13,4 @@
 #define VMALLOC_OFFSET	  (8*1024*1024)
 #define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-ebsa110/hardware.h	Tue Apr 11 15:09:23 2000
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Tue Apr 25 16:54:38 2000
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/hardware.h
  *
- * Copyright (C) 1996-1999 Russell King.
+ * Copyright (C) 1996-2000 Russell King.
  *
  * This file contains the hardware definitions of the EBSA-110.
  */
@@ -27,7 +27,6 @@
  * RAM definitions
  */
 #define FLUSH_BASE_PHYS		0x40000000
-#define UNCACHEABLE_ADDR	0xf3000000
 
 #else	/* __ASSEMBLY__ */
 
@@ -40,6 +39,8 @@
 
 #define FLUSH_BASE		0xdf000000
 #define PCIO_BASE		0xf0000000
+
+#define UNCACHEABLE_ADDR	0xf3000000
 
 #define PARAMS_BASE		(PAGE_OFFSET + 0x400)
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-ebsa285/irq.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Tue Apr 25 16:54:38 2000
@@ -212,5 +212,14 @@
 		request_resource(&ioport_resource, &pic2_resource);
 		setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
 		setup_arm_irq(isa_irq, &irq_cascade);
+
+		/*
+		 * On the NetWinder, don't automatically
+		 * enable ISA IRQ11 when it is requested.
+		 * There appears to be a missing pull-up
+		 * resistor on this line.
+		 */
+		if (machine_is_netwinder())
+			irq_desc[_ISA_IRQ(11)].noautoenable = 1;
 	}
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-ebsa285/time.h	Tue Mar 14 19:10:40 2000
+++ linux/include/asm-arm/arch-ebsa285/time.h	Tue Apr 25 16:54:38 2000
@@ -270,5 +270,5 @@
 		timer_irq.handler = isa_timer_interrupt;
 		irq = IRQ_ISA_TIMER;
 	}
-	setup_arm_irq(IRQ_ISA_TIMER, &timer_irq);
+	setup_arm_irq(irq, &timer_irq);
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-ebsa285/timex.h linux/include/asm-arm/arch-ebsa285/timex.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-ebsa285/timex.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa285/timex.h	Tue Apr 25 16:54:38 2000
@@ -11,4 +11,4 @@
  * divided by a 4-bit prescaler.  Other boards use an
  * ISA derived timer, and this is unused.
  */
-#define CLOCK_TICK_RATE		(50000000 / 16)
+#define CLOCK_TICK_RATE		(mem_fclk_21285 / 16)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-rpc/hardware.h	Tue Apr 11 15:09:23 2000
+++ linux/include/asm-arm/arch-rpc/hardware.h	Tue Apr 25 16:54:38 2000
@@ -33,10 +33,8 @@
 #define IO_BASE			0xe0000000
 
 #define SCREEN_START		0x02000000	/* VRAM */
-#define SCREEN2_END		0xe0000000
-#define SCREEN2_BASE		0xd8000000
-#define SCREEN1_END		0xd8000000
-#define SCREEN1_BASE		0xd0000000
+#define SCREEN_END		0xdfc00000
+#define SCREEN_BASE		0xdf800000
 
 #define FLUSH_BASE		0xdf000000
 #define UNCACHEABLE_ADDR	0xdf010000
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/arch-rpc/vmalloc.h linux/include/asm-arm/arch-rpc/vmalloc.h
--- v2.3.99-pre5/linux/include/asm-arm/arch-rpc/vmalloc.h	Tue Apr 11 15:09:23 2000
+++ linux/include/asm-arm/arch-rpc/vmalloc.h	Tue Apr 25 16:54:38 2000
@@ -13,4 +13,4 @@
 #define VMALLOC_OFFSET	  (8*1024*1024)
 #define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/atomic.h linux/include/asm-arm/atomic.h
--- v2.3.99-pre5/linux/include/asm-arm/atomic.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/atomic.h	Tue Apr 25 16:54:38 2000
@@ -12,11 +12,11 @@
 #ifndef __ASM_ARM_ATOMIC_H
 #define __ASM_ARM_ATOMIC_H
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 #error SMP not supported
 #endif
-
-#include <linux/config.h>
 
 #ifdef CONFIG_ARCH_CO285
 typedef struct { volatile int counter; } atomic_t;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h
--- v2.3.99-pre5/linux/include/asm-arm/hardirq.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-arm/hardirq.h	Tue Apr 25 16:54:38 2000
@@ -1,6 +1,7 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
@@ -14,7 +15,7 @@
 
 #define in_irq() (local_irq_count[smp_processor_id()] != 0)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
@@ -26,6 +27,6 @@
 
 #else
 #error SMP not supported
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #endif /* __ASM_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- v2.3.99-pre5/linux/include/asm-arm/pci.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/pci.h	Tue Apr 25 16:54:38 2000
@@ -51,7 +51,7 @@
 extern inline dma_addr_t
 pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
-	consistent_sync(ptr, size, 3);
+	consistent_sync(ptr, size, direction);
 	return virt_to_bus(ptr);
 }
 
@@ -89,7 +89,7 @@
 	int i;
 
 	for (i = 0; i < nents; i++, sg++)
-		consistent_sync(sg->address, sg->length, 3);
+		consistent_sync(sg->address, sg->length, direction);
 
 	return nents;
 }
@@ -116,7 +116,7 @@
 extern inline void
 pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
 {
-	consistent_sync(bus_to_virt(dma_handle), size, 3);
+	consistent_sync(bus_to_virt(dma_handle), size, direction);
 }
 
 /* Make physical memory consistent for a set of streaming
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/pgalloc.h linux/include/asm-arm/pgalloc.h
--- v2.3.99-pre5/linux/include/asm-arm/pgalloc.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-arm/pgalloc.h	Tue Apr 25 16:54:38 2000
@@ -25,9 +25,9 @@
  */
 #ifndef CONFIG_NO_PGT_CACHE
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif	/* __SMP__ */
+#endif	/* CONFIG_SMP */
 
 extern struct pgtable_cache_struct {
 	unsigned long *pgd_cache;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.3.99-pre5/linux/include/asm-arm/pgtable.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-arm/pgtable.h	Tue Apr 25 16:54:38 2000
@@ -83,9 +83,9 @@
 #define pmd_clear(pmdp)		set_pmd(pmdp, __pmd(0))
 
 /*
- * Permanent address of a page.
+ * Permanent address of a page. We never have highmem, so this is trivial.
  */
-#define page_address(page)	({ if (!(page)->virtual) BUG(); (page)->virtual; })
+#define page_address(page)	((page)->virtual)
 #define pages_to_mb(x)		((x) >> (20 - PAGE_SHIFT))
 #define pte_page(x)		(mem_map + pte_pagenr(x))
 
@@ -100,13 +100,12 @@
 	return pte;
 }
 
-#define mk_pte(page,pgprot)					\
-({								\
-	pte_t __pte;						\
-	pte_val(__pte) = PHYS_OFFSET + 				\
-			  (((page) - mem_map) << PAGE_SHIFT) +	\
-			   pgprot_val(pgprot);			\
-	__pte;							\
+#define mk_pte(page,pgprot)				\
+({							\
+	pte_t __pte;					\
+	pte_val(__pte) = __pa(page_address(page)) +	\
+			   pgprot_val(pgprot);		\
+	__pte;						\
 })
 
 /*
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/proc-armo/elf.h linux/include/asm-arm/proc-armo/elf.h
--- v2.3.99-pre5/linux/include/asm-arm/proc-armo/elf.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/proc-armo/elf.h	Thu Apr 13 08:11:49 2000
@@ -10,7 +10,6 @@
 #define ELF_PROC_OK(x)		\
 	((x)->e_flags & EF_ARM_APCS26)
 
-#define SET_PERSONALITY(ex,ibcs2) \
-	current->personality = PER_LINUX
+#define SET_PERSONALITY(ex,ibcs2) set_personality(PER_LINUX)
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/proc-armo/system.h linux/include/asm-arm/proc-armo/system.h
--- v2.3.99-pre5/linux/include/asm-arm/proc-armo/system.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/proc-armo/system.h	Tue Apr 25 16:54:38 2000
@@ -9,6 +9,7 @@
 
 extern const char xchg_str[];
 
+#include <linux/config.h>
 #include <asm/proc-fns.h>
 
 extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
@@ -113,7 +114,7 @@
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #error SMP not supported
 #else
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/proc-armv/elf.h linux/include/asm-arm/proc-armv/elf.h
--- v2.3.99-pre5/linux/include/asm-arm/proc-armv/elf.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/proc-armv/elf.h	Thu Apr 13 08:11:49 2000
@@ -17,7 +17,6 @@
    there is no other ELF system currently supported by iBCS.
    @@ Could print a warning message to encourage users to upgrade.  */
 #define SET_PERSONALITY(ex,ibcs2) \
-	current->personality = (ex.e_flags & EF_ARM_APCS26) ? \
-	PER_LINUX : PER_LINUX_32BIT
+	set_personality((ex).e_flags&EF_ARM_APCS26 ?PER_LINUX :PER_LINUX_32BIT)
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.3.99-pre5/linux/include/asm-arm/proc-armv/pgtable.h	Tue Apr 11 15:09:23 2000
+++ linux/include/asm-arm/proc-armv/pgtable.h	Tue Apr 25 16:54:38 2000
@@ -79,7 +79,7 @@
 * PTE functions *
 ****************/
 
-/* PTE types (actially level 2 descriptor) */
+/* PTE types (actually level 2 descriptor) */
 #define PTE_TYPE_MASK		0x0003
 #define PTE_TYPE_FAULT		0x0000
 #define PTE_TYPE_LARGE		0x0001
@@ -122,12 +122,12 @@
  * The following macros handle the cache and bufferable bits...
  */
 #define _L_PTE_DEFAULT	L_PTE_PRESENT | L_PTE_YOUNG
-#define _L_PTE_READ	L_PTE_USER | L_PTE_CACHEABLE
+#define _L_PTE_READ	L_PTE_USER | L_PTE_CACHEABLE | L_PTE_BUFFERABLE
 
 #define PAGE_NONE       __pgprot(_L_PTE_DEFAULT)
-#define PAGE_COPY       __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE)
-#define PAGE_SHARED     __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE | L_PTE_WRITE)
-#define PAGE_READONLY   __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE)
+#define PAGE_COPY       __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_SHARED     __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
+#define PAGE_READONLY   __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
 #define PAGE_KERNEL     __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
 
 #define _PAGE_CHG_MASK	(PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h
--- v2.3.99-pre5/linux/include/asm-arm/proc-armv/system.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-arm/proc-armv/system.h	Tue Apr 25 16:54:38 2000
@@ -7,6 +7,8 @@
 #ifndef __ASM_PROC_SYSTEM_H
 #define __ASM_PROC_SYSTEM_H
 
+#include <linux/config.h>
+
 extern const char xchg_str[];
 
 extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
@@ -106,7 +108,7 @@
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #error SMP not supported
 #else
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/setup.h linux/include/asm-arm/setup.h
--- v2.3.99-pre5/linux/include/asm-arm/setup.h	Mon Nov  1 13:56:27 1999
+++ linux/include/asm-arm/setup.h	Tue Apr 25 16:54:38 2000
@@ -49,6 +49,7 @@
 	    unsigned long system_rev;		/* 76 */
 	    unsigned long system_serial_low;	/* 80 */
 	    unsigned long system_serial_high;	/* 84 */
+	    unsigned long mem_fclk_21285;       /* 88 */ 
 	} s;
 	char unused[256];
     } u1;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/smp.h linux/include/asm-arm/smp.h
--- v2.3.99-pre5/linux/include/asm-arm/smp.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-arm/smp.h	Tue Apr 25 16:54:38 2000
@@ -1,7 +1,9 @@
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 #error SMP not supported
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/string.h linux/include/asm-arm/string.h
--- v2.3.99-pre5/linux/include/asm-arm/string.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-arm/string.h	Tue Apr 25 16:54:38 2000
@@ -15,6 +15,8 @@
 #define __HAVE_ARCH_MEMCPY
 #define __HAVE_ARCH_MEMMOVE
 #define __HAVE_ARCH_MEMCHR
+extern void * memchr(const void *cs, int c, size_t count);
+
 #define __HAVE_ARCH_MEMZERO
 #define __HAVE_ARCH_MEMSET
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-arm/system.h linux/include/asm-arm/system.h
--- v2.3.99-pre5/linux/include/asm-arm/system.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-arm/system.h	Tue Apr 25 16:54:38 2000
@@ -11,11 +11,12 @@
 extern unsigned int system_rev;
 extern unsigned int system_serial_low;
 extern unsigned int system_serial_high;
+extern unsigned int mem_fclk_21285;
 
 /* The type of machine we're running on */
 extern unsigned int __machine_arch_type;
 
-/* see arch/arm/kernel/setup.c for a description of these */
+/* see arch/arm/kernel/arch.c for a description of these */
 #define MACH_TYPE_EBSA110		0
 #define MACH_TYPE_RISCPC		1
 #define MACH_TYPE_NEXUSPCI		3
@@ -31,8 +32,13 @@
 #define MACH_TYPE_LACIE_NAS		13
 #define MACH_TYPE_CLPS7500		14
 #define MACH_TYPE_SHARK			15
-#define MACH_TYPE_SA1100		16
+#define MACH_TYPE_BRUTUS		16
 #define MACH_TYPE_PERSONAL_SERVER	17
+#define MACH_TYPE_BITSY			22
+#define MACH_TYPE_THINCLIENT		24
+#define MACH_TYPE_ASSABET		25
+#define MACH_TYPE_VICTOR		26
+#define MACH_TYPE_LART			27
 
 /*
  * Sort out a definition for machine_arch_type
@@ -168,16 +174,16 @@
 # define machine_is_shark()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_SA1100
+#ifdef CONFIG_SA1100_BRUTUS
 # ifdef machine_arch_type
 #  undef machine_arch_type
 #  define machine_arch_type	__machine_arch_type
 # else
-#  define machine_arch_type	MACH_TYPE_SA1100
+#  define machine_arch_type	MACH_TYPE_BRUTUS
 # endif
-# define machine_is_sa1100()	(machine_arch_type == MACH_TYPE_SA1100)
+# define machine_is_brutus()	(machine_arch_type == MACH_TYPE_BRUTUS)
 #else
-# define machine_is_sa1100()	(0)
+# define machine_is_brutus()	(0)
 #endif
 
 #ifdef CONFIG_ARCH_PERSONAL_SERVER
@@ -190,6 +196,126 @@
 # define machine_is_personal_server()	(machine_arch_type == MACH_TYPE_PERSONAL_SERVER)
 #else
 # define machine_is_personal_server()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_ITSY
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_ITSY
+# endif
+# define machine_is_itsy()	(machine_arch_type == MACH_TYPE_ITSY)
+#else
+# define machine_is_itsy()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_EMPEG
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_EMPEG
+# endif
+# define machine_is_empeg()	(machine_arch_type == MACH_TYPE_EMPEG)
+#else
+# define machine_is_empeg()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_ASSABET
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_ASSABET
+# endif
+# define machine_is_assabet()	(machine_arch_type == MACH_TYPE_ASSABET)
+#else
+# define machine_is_assabet()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_VICTOR
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_VICTOR
+# endif
+# define machine_is_victor()	(machine_arch_type == MACH_TYPE_VICTOR)
+#else
+# define machine_is_victor()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_LART
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_LART
+# endif
+# define machine_is_lart()	(machine_arch_type == MACH_TYPE_LART)
+#else
+# define machine_is_lart()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_BITSY
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_BITSY
+# endif
+# define machine_is_bitsy()	(machine_arch_type == MACH_TYPE_BITSY)
+#else
+# define machine_is_bitsy()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_TIFON
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_TIFON
+# endif
+# define machine_is_tifon()	(machine_arch_type == MACH_TYPE_TIFON)
+#else
+# define machine_is_tifon()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_PLEB
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_PLEB
+# endif
+# define machine_is_pleb()	(machine_arch_type == MACH_TYPE_PLEB)
+#else
+# define machine_is_pleb()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_THINCLIENT
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_THINCLIENT
+# endif
+# define machine_is_thinclient()	(machine_arch_type == MACH_TYPE_THINCLIENT)
+#else
+# define machine_is_thinclient()	(0)
+#endif
+
+#ifdef CONFIG_SA1100_PENNY
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_PENNY
+# endif
+# define machine_is_penny()	(machine_arch_type == MACH_TYPE_PENNY)
+#else
+# define machine_is_penny()	(0)
 #endif
 
 #ifndef machine_arch_type
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/apic.h linux/include/asm-i386/apic.h
--- v2.3.99-pre5/linux/include/asm-i386/apic.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-i386/apic.h	Wed Apr 26 15:29:07 2000
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <asm/apicdef.h>
+#include <asm/system.h>
 
 #define APIC_DEBUG 1
 
@@ -20,7 +21,12 @@
 
 extern __inline void apic_write(unsigned long reg, unsigned long v)
 {
-	*((volatile unsigned long *)(APIC_BASE+reg))=v;
+	*((volatile unsigned long *)(APIC_BASE+reg)) = v;
+}
+
+extern __inline void apic_write_atomic(unsigned long reg, unsigned long v)
+{
+	xchg((volatile unsigned long *)(APIC_BASE+reg), v);
 }
 
 extern __inline unsigned long apic_read(unsigned long reg)
@@ -32,30 +38,33 @@
 
 #ifdef CONFIG_X86_GOOD_APIC
 # define FORCE_READ_AROUND_WRITE 0
-# define apic_readaround(x)
+# define apic_read_around(x)
+# define apic_write_around(x,y) apic_write((x),(y))
 #else
 # define FORCE_READ_AROUND_WRITE 1
-# define apic_readaround(x) apic_read(x)
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write_atomic((x),(y))
 #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.
+	 * ack_APIC_irq() actually gets compiled as a single instruction:
+	 * - a single rmw on Pentium/82489DX
+	 * - a single write on P6+ cores (CONFIG_X86_GOOD_APIC)
+	 * ... yummie.
 	 */
-        apic_write(APIC_EOI, 0); /* Docs say use 0 for future compatibility */
+
+	/* Docs say use 0 for future compatibility */
+	apic_write_around(APIC_EOI, 0);
 }
 
 extern int get_maxlvt(void);
+extern void connect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (void);
 extern void disable_local_APIC (void);
 extern void cache_APIC_registers (void);
+extern void sync_Arb_IDs(void);
 extern void setup_local_APIC (void);
 extern void init_apic_mappings(void);
 extern void smp_local_timer_interrupt(struct pt_regs * regs);
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/apicdef.h linux/include/asm-i386/apicdef.h
--- v2.3.99-pre5/linux/include/asm-i386/apicdef.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-i386/apicdef.h	Wed Apr 12 09:33:19 2000
@@ -29,8 +29,6 @@
 #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)
 #define		APIC_SPIV	0xF0
 #define		APIC_ISR	0x100
 #define		APIC_TMR	0x180
@@ -47,22 +45,23 @@
 #define			APIC_DEST_SELF		0x40000
 #define			APIC_DEST_ALLINC	0x80000
 #define			APIC_DEST_ALLBUT	0xC0000
-#define			APIC_DEST_RR_MASK	0x30000
-#define			APIC_DEST_RR_INVALID	0x00000
-#define			APIC_DEST_RR_INPROG	0x10000
-#define			APIC_DEST_RR_VALID	0x20000
-#define			APIC_DEST_LEVELTRIG	0x08000
-#define			APIC_DEST_ASSERT	0x04000
-#define			APIC_DEST_BUSY		0x01000
+#define			APIC_ICR_RR_MASK	0x30000
+#define			APIC_ICR_RR_INVALID	0x00000
+#define			APIC_ICR_RR_INPROG	0x10000
+#define			APIC_ICR_RR_VALID	0x20000
+#define			APIC_INT_LEVELTRIG	0x08000
+#define			APIC_INT_ASSERT		0x04000
+#define			APIC_ICR_BUSY		0x01000
 #define			APIC_DEST_LOGICAL	0x00800
-#define			APIC_DEST_DM_FIXED	0x00000
-#define			APIC_DEST_DM_LOWEST	0x00100
-#define			APIC_DEST_DM_SMI	0x00200
-#define			APIC_DEST_DM_REMRD	0x00300
-#define			APIC_DEST_DM_NMI	0x00400
-#define			APIC_DEST_DM_INIT	0x00500
-#define			APIC_DEST_DM_STARTUP	0x00600
-#define			APIC_DEST_VECTOR_MASK	0x000FF
+#define			APIC_DM_FIXED		0x00000
+#define			APIC_DM_LOWEST		0x00100
+#define			APIC_DM_SMI		0x00200
+#define			APIC_DM_REMRD		0x00300
+#define			APIC_DM_NMI		0x00400
+#define			APIC_DM_INIT		0x00500
+#define			APIC_DM_STARTUP		0x00600
+#define			APIC_DM_EXTINT		0x00700
+#define			APIC_VECTOR_MASK	0x000FF
 #define		APIC_ICR2	0x310
 #define			GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
 #define			SET_APIC_DEST_FIELD(x)	((x)<<24)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h
--- v2.3.99-pre5/linux/include/asm-i386/atomic.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-i386/atomic.h	Wed Apr 26 15:29:06 2000
@@ -1,12 +1,14 @@
 #ifndef __ARCH_I386_ATOMIC__
 #define __ARCH_I386_ATOMIC__
 
+#include <linux/config.h>
+
 /*
  * Atomic operations that C can't guarantee us.  Useful for
  * resource counting etc..
  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define LOCK "lock ; "
 #else
 #define LOCK ""
@@ -19,7 +21,7 @@
  */
 #define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 typedef struct { volatile int counter; } atomic_t;
 #else
 typedef struct { int counter; } atomic_t;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v2.3.99-pre5/linux/include/asm-i386/bitops.h	Tue Dec 14 01:27:24 1999
+++ linux/include/asm-i386/bitops.h	Wed Apr 26 15:29:06 2000
@@ -5,6 +5,8 @@
  * Copyright 1992, Linus Torvalds.
  */
 
+#include <linux/config.h>
+
 /*
  * These have to be done with inline assembly: that way the bit-setting
  * is guaranteed to be atomic. All bit operations return 0 if the bit
@@ -13,7 +15,7 @@
  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define LOCK_PREFIX "lock ; "
 #else
 #define LOCK_PREFIX ""
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.3.99-pre5/linux/include/asm-i386/bugs.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-i386/bugs.h	Wed Apr 26 15:29:05 2000
@@ -21,8 +21,6 @@
 #include <asm/processor.h>
 #include <asm/msr.h>
 
-#define CONFIG_BUGi386
-
 static int __init no_halt(char *s)
 {
 	boot_cpu_data.hlt_works_ok = 0;
@@ -370,16 +368,18 @@
 }
  
 /*
- * Check wether we are able to run this kernel safely on SMP.
+ * Check whether we are able to run this kernel safely on SMP.
  *
  * - In order to run on a i386, we need to be compiled for i386
  *   (for due to lack of "invlpg" and working WP on a i386)
  * - In order to run on anything without a TSC, we need to be
  *   compiled for a i486.
- * - In order to work on a Pentium/SMP machine, we need to be
- *   compiled for a Pentium or lower, as a PPro config implies
- *   a properly working local APIC without the need to do extra
- *   reads from the APIC.
+ * - In order to support the local APIC on a buggy Pentium machine,
+ *   we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
+ *   which happens implicitly if compiled for a Pentium or lower
+ *   (unless an advanced selection of CPU features is used) as an
+ *   otherwise config implies a properly working local APIC without
+ *   the need to do extra reads from the APIC.
 */
 
 static void __init check_config(void)
@@ -411,11 +411,18 @@
 #endif
 
 /*
- * If we were told we had a good APIC for SMP, we'd better be a PPro
- */
-#if defined(CONFIG_X86_GOOD_APIC) && defined(CONFIG_SMP)
-	if (smp_found_config && boot_cpu_data.x86 <= 5)
-		panic("Kernel compiled for PPro+, assumes local APIC without read-before-write bug");
+ * If we were told we had a good local APIC, check for buggy Pentia,
+ * i.e. all B steppings and the C2 stepping of P54C when using their
+ * integrated APIC (see 11AP erratum in "Pentium Processor
+ * Specification Update").
+ */
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
+	    && boot_cpu_data.x86_capability & X86_FEATURE_APIC
+	    && boot_cpu_data.x86 == 5
+	    && boot_cpu_data.x86_model == 2
+	    && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
+		panic("Kernel compiled for PPro+, assumes a local APIC without the read-before-write bug!");
 #endif
 }
 
@@ -425,7 +432,7 @@
 	identify_cpu(&boot_cpu_data);
 	check_cx686_cpuid();
 	check_cx686_slop();
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	printk("CPU: ");
 	print_cpu_info(&boot_cpu_data);
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/elf.h linux/include/asm-i386/elf.h
--- v2.3.99-pre5/linux/include/asm-i386/elf.h	Wed Aug 18 16:45:10 1999
+++ linux/include/asm-i386/elf.h	Wed Apr 26 15:29:43 2000
@@ -94,8 +94,7 @@
 #define ELF_PLATFORM  ("i386\0i486\0i586\0i686"+((boot_cpu_data.x86-3)*5))
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) \
-	current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 #endif
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h
--- v2.3.99-pre5/linux/include/asm-i386/hardirq.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-i386/hardirq.h	Wed Apr 26 15:29:07 2000
@@ -1,6 +1,7 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/irq.h>
 
@@ -29,7 +30,7 @@
 
 #define in_irq() (local_irq_count(smp_processor_id()) != 0)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define hardirq_trylock(cpu)	(local_irq_count(cpu) == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
@@ -89,6 +90,6 @@
 
 extern void synchronize_irq(void);
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #endif /* __ASM_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/hw_irq.h linux/include/asm-i386/hw_irq.h
--- v2.3.99-pre5/linux/include/asm-i386/hw_irq.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-i386/hw_irq.h	Wed Apr 26 15:29:06 2000
@@ -12,6 +12,7 @@
  *	<tomsoft@informatik.tu-chemnitz.de>
  */
 
+#include <linux/config.h>
 #include <asm/irq.h>
 
 /*
@@ -211,7 +212,7 @@
 	atomic_inc((atomic_t *)&prof_buffer[eip]);
 }
 
-#ifdef __SMP__ /*more of this file should probably be ifdefed SMP */
+#ifdef CONFIG_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));
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/mca_dma.h linux/include/asm-i386/mca_dma.h
--- v2.3.99-pre5/linux/include/asm-i386/mca_dma.h	Tue Mar 14 19:10:40 2000
+++ linux/include/asm-i386/mca_dma.h	Wed Apr 12 09:47:29 2000
@@ -178,18 +178,18 @@
 /**
  *	mca_set_dma_mode -	set the DMA mode
  *	@dmanr: DMA channel
- *	@mode: The mode to set
+ *	@mode: mode to set
  *
  *	The DMA controller supports several modes. The mode values you can
- *	set are 
+ *	set are :
  *
- *	MCA_DMA_MODE_READ when reading from the DMA device.
+ *	%MCA_DMA_MODE_READ when reading from the DMA device.
  *
- *	MCA_DMA_MODE_WRITE to writing to the DMA device.
+ *	%MCA_DMA_MODE_WRITE to writing to the DMA device.
  *
- *	MCA_DMA_MODE_IO to do DMA to or from an I/O port.
+ *	%MCA_DMA_MODE_IO to do DMA to or from an I/O port.
  *
- *	MCA_DMA_MODE_16 to do 16bit transfers.
+ *	%MCA_DMA_MODE_16 to do 16bit transfers.
  *
  */
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- v2.3.99-pre5/linux/include/asm-i386/mmu_context.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-i386/mmu_context.h	Wed Apr 26 15:29:07 2000
@@ -12,7 +12,7 @@
 #define destroy_context(mm)		do { } while(0)
 #define init_new_context(tsk,mm)	do { } while (0)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
@@ -42,7 +42,7 @@
 		asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));
 		clear_bit(cpu, &prev->cpu_vm_mask);
 	}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	else {
 		int old_state = cpu_tlbstate[cpu].state;
 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/mpspec.h linux/include/asm-i386/mpspec.h
--- v2.3.99-pre5/linux/include/asm-i386/mpspec.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-i386/mpspec.h	Wed Apr 12 09:33:19 2000
@@ -13,6 +13,11 @@
  
 #define SMP_MAGIC_IDENT	(('_'<<24)|('P'<<16)|('M'<<8)|'_')
 
+/*
+ * a maximum of 16 APICs with the current APIC ID architecture.
+ */
+#define MAX_APICS 16
+
 struct intel_mp_floating
 {
 	char mpf_signature[4];		/* "_MP_" 			*/
@@ -144,7 +149,8 @@
 enum mp_bustype {
 	MP_BUS_ISA,
 	MP_BUS_EISA,
-	MP_BUS_PCI
+	MP_BUS_PCI,
+	MP_BUS_MCA
 };
 extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
@@ -155,7 +161,7 @@
 extern void find_smp_config (void);
 extern void get_smp_config (void);
 extern int nr_ioapics;
-extern int apic_version [NR_CPUS];
+extern int apic_version [MAX_APICS];
 extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_irq_entries;
 extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/mtrr.h linux/include/asm-i386/mtrr.h
--- v2.3.99-pre5/linux/include/asm-i386/mtrr.h	Wed Aug 18 16:45:24 1999
+++ linux/include/asm-i386/mtrr.h	Wed Apr 26 15:29:10 2000
@@ -95,7 +95,7 @@
 
 /*  The following functions are for initialisation: don't use them!  */
 extern int mtrr_init (void);
-#  if defined(__SMP__) && defined(CONFIG_MTRR)
+#  if defined(CONFIG_SMP) && defined(CONFIG_MTRR)
 extern void mtrr_init_boot_cpu (void);
 extern void mtrr_init_secondary_cpu (void);
 #  endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- v2.3.99-pre5/linux/include/asm-i386/pgalloc.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-i386/pgalloc.h	Wed Apr 26 15:29:07 2000
@@ -156,7 +156,7 @@
 {
 	struct task_struct * p;
 	pgd_t *pgd;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int i;
 #endif	
 
@@ -167,7 +167,7 @@
 		*pgd_offset(p->mm,address) = entry;
 	}
 	read_unlock(&tasklist_lock);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
 		pgd[address >> PGDIR_SHIFT] = entry;
 #else
@@ -193,7 +193,7 @@
  * and page-granular flushes are available only on i486 and up.
  */
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define flush_tlb() __flush_tlb()
 #define flush_tlb_all() __flush_tlb_all()
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.3.99-pre5/linux/include/asm-i386/processor.h	Sun Mar 19 18:35:31 2000
+++ linux/include/asm-i386/processor.h	Wed Apr 26 15:29:06 2000
@@ -12,6 +12,7 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/types.h>
+#include <linux/config.h>
 #include <linux/threads.h>
 
 /*
@@ -100,7 +101,7 @@
 extern struct cpuinfo_x86 boot_cpu_data;
 extern struct tss_struct init_tss[NR_CPUS];
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern struct cpuinfo_x86 cpu_data[];
 #define current_cpu_data cpu_data[smp_processor_id()]
 #else
@@ -356,7 +357,7 @@
 }
 
 #define start_thread(regs, new_eip, new_esp) do {		\
-	__asm__("movl %w0,%%fs ; movl %w0,%%gs": :"r" (0));	\
+	__asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0));	\
 	set_fs(USER_DS);					\
 	regs->xds = __USER_DS;					\
 	regs->xes = __USER_DS;					\
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/spinlock.h linux/include/asm-i386/spinlock.h
--- v2.3.99-pre5/linux/include/asm-i386/spinlock.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-i386/spinlock.h	Wed Apr 26 15:29:06 2000
@@ -33,7 +33,7 @@
 #define SPINLOCK_MAGIC_INIT	/* */
 #endif
 
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 SPINLOCK_MAGIC_INIT }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
 
 #define spin_lock_init(x)	do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
 /*
@@ -43,32 +43,39 @@
  * We make no fairness assumptions. They have a cost.
  */
 
-#define spin_unlock_wait(x)	do { barrier(); } while(((volatile spinlock_t *)(x))->lock)
-#define spin_is_locked(x)	((x)->lock != 0)
+#define spin_is_locked(x)	(*(volatile char *)(&(x)->lock) <= 0)
+#define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
 
 #define spin_lock_string \
 	"\n1:\t" \
-	"lock ; btsl $0,%0\n\t" \
-	"jc 2f\n" \
+	"lock ; decb %0\n\t" \
+	"js 2f\n" \
 	".section .text.lock,\"ax\"\n" \
 	"2:\t" \
-	"testb $1,%0\n\t" \
+	"cmpb $0,%0\n\t" \
 	"rep;nop\n\t" \
-	"jne 2b\n\t" \
+	"jle 2b\n\t" \
 	"jmp 1b\n" \
 	".previous"
 
 /*
- * Sadly, some early PPro chips require the locked access,
- * otherwise we could just always simply do
- *
- * 	#define spin_unlock_string \
- *		"movb $0,%0"
- *
- * Which is noticeably faster.
+ * This works. Despite all the confusion.
  */
 #define spin_unlock_string \
-	"lock ; btrl $0,%0"
+	"movb $1,%0"
+
+/*
+ * Won't work on i386-SMP. Does anybody care?
+ */
+static inline int spin_trylock(spinlock_t *lock)
+{
+	char oldval;
+	__asm__ __volatile__(
+		"lock ; cmpxchg %b2,%1"
+		:"=a" (oldval), "=m" (__dummy_lock(lock))
+		:"q" (0), "0" (1));
+	return oldval > 0;
+}
 
 extern inline void spin_lock(spinlock_t *lock)
 {
@@ -90,15 +97,13 @@
 #if SPINLOCK_DEBUG
 	if (lock->magic != SPINLOCK_MAGIC)
 		BUG();
-	if (!lock->lock)
+	if (!spin_is_locked(lock))
 		BUG();
 #endif
 	__asm__ __volatile__(
 		spin_unlock_string
 		:"=m" (__dummy_lock(lock)));
 }
-
-#define spin_trylock(lock) ({ !test_and_set_bit(0,(lock)); })
 
 /*
  * Read-write spinlocks, allowing multiple readers
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.3.99-pre5/linux/include/asm-i386/string.h	Mon Mar 27 08:08:31 2000
+++ linux/include/asm-i386/string.h	Wed Apr 26 15:29:07 2000
@@ -452,6 +452,36 @@
 }
 /* end of additional stuff */
 
+#define __HAVE_ARCH_STRSTR
+extern inline char * strstr(const char * cs,const char * ct)
+{
+int	d0, d1;
+register char * __res;
+__asm__ __volatile__(
+	"movl %6,%%edi\n\t"
+	"repne\n\t"
+	"scasb\n\t"
+	"notl %%ecx\n\t"
+	"decl %%ecx\n\t"	/* NOTE! This also sets Z if searchstring='' */
+	"movl %%ecx,%%edx\n"
+	"1:\tmovl %6,%%edi\n\t"
+	"movl %%esi,%%eax\n\t"
+	"movl %%edx,%%ecx\n\t"
+	"repe\n\t"
+	"cmpsb\n\t"
+	"je 2f\n\t"		/* also works for empty string, see above */
+	"xchgl %%eax,%%esi\n\t"
+	"incl %%esi\n\t"
+	"cmpb $0,-1(%%eax)\n\t"
+	"jne 1b\n\t"
+	"xorl %%eax,%%eax\n\t"
+	"2:"
+	:"=a" (__res), "=&c" (d0), "=&S" (d1)
+	:"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct)
+	:"dx", "di");
+return __res;
+}
+
 /*
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as we by now know that both pattern and count is constant..
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.3.99-pre5/linux/include/asm-i386/system.h	Mon Mar 27 08:08:31 2000
+++ linux/include/asm-i386/system.h	Wed Apr 26 15:29:06 2000
@@ -289,7 +289,7 @@
 #define local_irq_disable()	__asm__ __volatile__("cli": : :"memory")
 #define local_irq_enable()	__asm__ __volatile__("sti": : :"memory")
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 extern void __global_cli(void);
 extern void __global_sti(void);
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/atomic.h linux/include/asm-ia64/atomic.h
--- v2.3.99-pre5/linux/include/asm-ia64/atomic.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/atomic.h	Fri Apr 21 15:21:24 2000
@@ -44,7 +44,7 @@
 		CMPXCHG_BUGCHECK(v);
 		old = atomic_read(v);
 		new = old + i;
-	} while (ia64_cmpxchg(v, old, old + i, sizeof(atomic_t)) != old);
+	} while (ia64_cmpxchg("acq", v, old, old + i, sizeof(atomic_t)) != old);
 	return new;
 }
 
@@ -58,7 +58,7 @@
 		CMPXCHG_BUGCHECK(v);
 		old = atomic_read(v);
 		new = old - i;
-	} while (ia64_cmpxchg(v, old, new, sizeof(atomic_t)) != old);
+	} while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old);
 	return new;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/bitops.h linux/include/asm-ia64/bitops.h
--- v2.3.99-pre5/linux/include/asm-ia64/bitops.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/bitops.h	Fri Apr 21 15:21:24 2000
@@ -33,7 +33,7 @@
 		CMPXCHG_BUGCHECK(m);
 		old = *m;
 		new = old | bit;
-	} while (cmpxchg(m, old, new) != old);
+	} while (cmpxchg_acq(m, old, new) != old);
 }
 
 extern __inline__ void
@@ -49,7 +49,7 @@
 		CMPXCHG_BUGCHECK(m);
 		old = *m;
 		new = old & mask;
-	} while (cmpxchg(m, old, new) != old);
+	} while (cmpxchg_acq(m, old, new) != old);
 }
 
 extern __inline__ void
@@ -65,7 +65,7 @@
 		CMPXCHG_BUGCHECK(m);
 		old = *m;
 		new = old ^ bit;
-	} while (cmpxchg(m, old, new) != old);
+	} while (cmpxchg_acq(m, old, new) != old);
 }
 
 extern __inline__ int
@@ -81,7 +81,7 @@
 		CMPXCHG_BUGCHECK(m);
 		old = *m;
 		new = old | bit;
-	} while (cmpxchg(m, old, new) != old);
+	} while (cmpxchg_acq(m, old, new) != old);
 	return (old & bit) != 0;
 }
 
@@ -98,7 +98,7 @@
 		CMPXCHG_BUGCHECK(m);
 		old = *m;
 		new = old & mask;
-	} while (cmpxchg(m, old, new) != old);
+	} while (cmpxchg_acq(m, old, new) != old);
 	return (old & ~mask) != 0;
 }
 
@@ -115,7 +115,7 @@
 		CMPXCHG_BUGCHECK(m);
 		old = *m;
 		new = old ^ bit;
-	} while (cmpxchg(m, old, new) != old);
+	} while (cmpxchg_acq(m, old, new) != old);
 	return (old & bit) != 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/cache.h linux/include/asm-ia64/cache.h
--- v2.3.99-pre5/linux/include/asm-ia64/cache.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/cache.h	Fri Apr 21 15:21:24 2000
@@ -1,12 +1,28 @@
 #ifndef _ASM_IA64_CACHE_H
 #define _ASM_IA64_CACHE_H
 
+#include <linux/config.h>
+
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 /* Bytes per L1 (data) cache line.  */
-#define L1_CACHE_BYTES		64
+#define LOG_L1_CACHE_BYTES	6
+#define L1_CACHE_BYTES		(1 << LOG_L1_CACHE_BYTES)
+
+#ifdef CONFIG_SMP
+# define SMP_LOG_CACHE_BYTES	LOG_L1_CACHE_BYTES
+# define SMP_CACHE_BYTES	L1_CACHE_BYTES
+#else
+  /*
+   * The "aligned" directive can only _increase_ alignment, so this is
+   * safe and provides an easy way to avoid wasting space on a
+   * uni-processor:
+   */
+# define SMP_LOG_CACHE_BYTES	3
+# define SMP_CACHE_BYTES	(1 << 3)
+#endif
 
 #endif /* _ASM_IA64_CACHE_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/current.h linux/include/asm-ia64/current.h
--- v2.3.99-pre5/linux/include/asm-ia64/current.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/current.h	Fri Apr 21 15:21:24 2000
@@ -2,8 +2,8 @@
 #define _ASM_IA64_CURRENT_H
 
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 /* In kernel mode, thread pointer (r13) is used to point to the
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/elf.h linux/include/asm-ia64/elf.h
--- v2.3.99-pre5/linux/include/asm-ia64/elf.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/elf.h	Thu Apr 13 08:11:49 2000
@@ -82,8 +82,7 @@
 #define ELF_PLATFORM	0
 
 #ifdef __KERNEL__
-# define SET_PERSONALITY(EX,IBCS2)				\
-	(current->personality = (IBCS2) ? PER_SVR4 : PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 #endif
 
 #endif /* _ASM_IA64_ELF_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/hardirq.h linux/include/asm-ia64/hardirq.h
--- v2.3.99-pre5/linux/include/asm-ia64/hardirq.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/hardirq.h	Fri Apr 21 15:21:24 2000
@@ -54,8 +54,8 @@
 #include <asm/atomic.h>
 #include <asm/smp.h>
 
-extern unsigned char global_irq_holder;
-extern unsigned volatile int global_irq_lock;
+extern unsigned int global_irq_holder;
+extern volatile unsigned int global_irq_lock;
 
 static inline int irqs_running (void)
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/hw_irq.h linux/include/asm-ia64/hw_irq.h
--- v2.3.99-pre5/linux/include/asm-ia64/hw_irq.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/hw_irq.h	Fri Apr 21 15:21:24 2000
@@ -11,8 +11,7 @@
 #include <linux/types.h>
 
 #include <asm/ptrace.h>
-
-#define NR_ISA_IRQS	 16
+#include <asm/smp.h>
 
 /*
  * 0 special
@@ -42,6 +41,8 @@
 
 /* IA64 inter-cpu interrupt related definitions */
 
+#define IPI_DEFAULT_BASE_ADDR	0xfee00000
+
 /* Delivery modes for inter-cpu interrupts */
 enum {
         IA64_IPI_DM_INT =       0x0,    /* pend an external interrupt */
@@ -57,20 +58,26 @@
 extern __u8 isa_irq_to_vector_map[16];
 #define isa_irq_to_vector(x)	isa_irq_to_vector_map[(x)]
 
-extern struct hw_interrupt_type irq_type_ia64_internal;	/* CPU-internal interrupt controller */
+extern unsigned long ipi_base_addr;
 
-extern void ipi_send (int cpu, int vector, int delivery_mode);
+extern struct hw_interrupt_type irq_type_ia64_sapic;	/* CPU-internal interrupt controller */
 
-#ifdef CONFIG_SMP
-extern void handle_IPI(int irq, void *dev_id, struct pt_regs *regs);
+extern void ipi_send (int cpu, int vector, int delivery_mode, int redirect);
 
 static inline void
-hw_resend_irq (struct hw_interrupt_type *h, unsigned int i)
+hw_resend_irq (struct hw_interrupt_type *h, unsigned int vector)
 {
-	send_IPI_self(i);
-}
+	int my_cpu_id;
+
+#ifdef CONFIG_SMP
+	my_cpu_id = smp_processor_id();
 #else
-# define hw_resend_irq(h,i)
+	__u64 lid;
+
+	__asm__ ("mov %0=cr.lid" : "=r"(lid));
+	my_cpu_id = (lid >> 24) & 0xff;		/* extract id (ignore eid) */
 #endif
+	ipi_send(my_cpu_id, vector, IA64_IPI_DM_INT, 0);
+}
 
 #endif /* _ASM_IA64_HW_IRQ_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/ia32.h linux/include/asm-ia64/ia32.h
--- v2.3.99-pre5/linux/include/asm-ia64/ia32.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/ia32.h	Fri Apr 21 15:21:24 2000
@@ -90,7 +90,7 @@
        unsigned int eflags;
        unsigned int esp_at_signal;
        unsigned short ss, __ssh;
-       struct _fpstate_ia32 * fpstate;
+       unsigned int fpstate;		/* really (struct _fpstate_ia32 *) */
        unsigned int oldmask;
        unsigned int cr2;
 };
@@ -221,8 +221,7 @@
 #define ELF_PLATFORM	0
 
 #ifdef __KERNEL__
-# define SET_PERSONALITY(EX,IBCS2)				\
-	(current->personality = (IBCS2) ? PER_SVR4 : PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 #endif
 
 #define IA32_EFLAG	0x200
@@ -288,9 +287,14 @@
  *  IA32 floating point control registers starting values
  */
 
-#define IA32_FSR_DEFAULT	0x555500000	/* set all tag bits */
+#define IA32_FSR_DEFAULT	0x55550000	/* set all tag bits */
 #define IA32_FCR_DEFAULT	0x33f		/* single precision, all masks */
 
+#define IA32_PTRACE_GETREGS	12
+#define IA32_PTRACE_SETREGS	13
+#define IA32_PTRACE_GETFPREGS	14
+#define IA32_PTRACE_SETFPREGS	15
+
 #define ia32_start_thread(regs,new_ip,new_sp) do {				\
 	set_fs(USER_DS);							\
 	ia64_psr(regs)->cpl = 3;	/* set user mode */			\
@@ -303,10 +307,11 @@
 } while (0)
 
 extern void ia32_gdt_init (void);
-extern long ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
+extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
 			       sigset_t *set, struct pt_regs *regs);
 extern void ia32_init_addr_space (struct pt_regs *regs);
 extern int ia32_setup_arg_pages (struct linux_binprm *bprm);
+extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
 
 #endif /* !CONFIG_IA32_SUPPORT */
  
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/ide.h linux/include/asm-ia64/ide.h
--- v2.3.99-pre5/linux/include/asm-ia64/ide.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/ide.h	Fri Apr 21 15:21:24 2000
@@ -15,6 +15,8 @@
 
 #include <linux/config.h>
 
+#include <linux/irq.h>
+
 #ifndef MAX_HWIFS
 # ifdef CONFIG_BLK_DEV_IDEPCI
 #define MAX_HWIFS	10
@@ -29,12 +31,12 @@
 ide_default_irq (ide_ioreg_t base)
 {
 	switch (base) {
-		case 0x1f0: return 14;
-		case 0x170: return 15;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		case 0x1e0: return 8;
-		case 0x160: return 12;
+		case 0x1f0: return isa_irq_to_vector(14);
+		case 0x170: return isa_irq_to_vector(15);
+		case 0x1e8: return isa_irq_to_vector(11);
+		case 0x168: return isa_irq_to_vector(10);
+		case 0x1e0: return isa_irq_to_vector(8);
+		case 0x160: return isa_irq_to_vector(12);
 		default:
 			return 0;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/io.h linux/include/asm-ia64/io.h
--- v2.3.99-pre5/linux/include/asm-ia64/io.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/io.h	Fri Apr 21 15:21:24 2000
@@ -13,8 +13,8 @@
  * over and over again with slight variations and possibly making a
  * mistake somewhere.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
  */
@@ -253,66 +253,66 @@
 /*
  * The address passed to these functions are ioremap()ped already.
  */
-extern inline unsigned long
-__readb (unsigned long addr)
+extern inline unsigned char
+__readb (void *addr)
 {
 	return *(volatile unsigned char *)addr;
 }
 
-extern inline unsigned long
-__readw (unsigned long addr)
+extern inline unsigned short
+__readw (void *addr)
 {
 	return *(volatile unsigned short *)addr;
 }
 
-extern inline unsigned long
-__readl (unsigned long addr)
+extern inline unsigned int
+__readl (void *addr)
 {
 	return *(volatile unsigned int *) addr;
 }
 
 extern inline unsigned long
-__readq (unsigned long addr)
+__readq (void *addr)
 {
 	return *(volatile unsigned long *) addr;
 }
 
 extern inline void
-__writeb (unsigned char val, unsigned long addr)
+__writeb (unsigned char val, void *addr)
 {
 	*(volatile unsigned char *) addr = val;
 }
 
 extern inline void
-__writew (unsigned short val, unsigned long addr)
+__writew (unsigned short val, void *addr)
 {
 	*(volatile unsigned short *) addr = val;
 }
 
 extern inline void
-__writel (unsigned int val, unsigned long addr)
+__writel (unsigned int val, void *addr)
 {
 	*(volatile unsigned int *) addr = val;
 }
 
 extern inline void
-__writeq (unsigned long val, unsigned long addr)
+__writeq (unsigned long val, void *addr)
 {
 	*(volatile unsigned long *) addr = val;
 }
 
-#define readb		__readb
-#define readw		__readw
-#define readl		__readl
-#define readq		__readqq
+#define readb(a)	__readb((void *)(a))
+#define readw(a)	__readw((void *)(a))
+#define readl(a)	__readl((void *)(a))
+#define readq(a)	__readqq((void *)(a))
 #define __raw_readb	readb
 #define __raw_readw	readw
 #define __raw_readl	readl
 #define __raw_readq	readq
-#define writeb		__writeb
-#define writew		__writew
-#define writel		__writel
-#define writeq		__writeq
+#define writeb(v,a)	__writeb((v), (void *) (a))
+#define writew(v,a)	__writew((v), (void *) (a))
+#define writel(v,a)	__writel((v), (void *) (a))
+#define writeq(v,a)	__writeq((v), (void *) (a))
 #define __raw_writeb	writeb
 #define __raw_writew	writew
 #define __raw_writeq	writeq
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/kdbsupport.h linux/include/asm-ia64/kdbsupport.h
--- v2.3.99-pre5/linux/include/asm-ia64/kdbsupport.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/kdbsupport.h	Wed Dec 31 16:00:00 1969
@@ -1,252 +0,0 @@
-#ifndef _ASM_IA64_KDBSUPPORT_H
-#define _ASM_IA64_KDBSUPPORT_H
-
-/*
- * Kernel Debugger Breakpoint Handler
- *
- * Copyright 1999, Silicon Graphics, Inc.
- *
- * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
- */
-
-#include <asm/ptrace.h>
-
-	/*
-	 * This file provides definitions for functions that
-	 * are dependent upon the product into which  kdb is
-	 * linked. 
-	 *
-	 * This version is for linux.
-	 */
-typedef void (*handler_t)(struct pt_regs *);
-typedef unsigned long k_machreg_t;
-
-unsigned long show_cur_stack_frame(struct pt_regs *, int, unsigned long *) ;
-
-extern char*         kbd_getstr(char *, size_t, char *);
-extern int           kdbinstalltrap(int, handler_t, handler_t*);
-extern int           kdbinstalldbreg(kdb_bp_t *);
-extern void          kdbremovedbreg(kdb_bp_t *);
-extern void          kdb_initbptab(void);
-extern int	     kdbgetregcontents(const char *, struct pt_regs *, unsigned long *);
-extern int	     kdbsetregcontents(const char *, struct pt_regs *, unsigned long);
-extern int	     kdbdumpregs(struct pt_regs *, const char *, const char *);
-
-typedef int kdbintstate_t;
-	
-extern void	     kdb_disableint(kdbintstate_t *);
-extern void	     kdb_restoreint(kdbintstate_t *);
-
-extern k_machreg_t   kdb_getpc(struct pt_regs *);
-extern int	     kdb_setpc(struct pt_regs *, k_machreg_t);
-
-extern int	     kdb_putword(unsigned long, unsigned long);
-extern int	     kdb_getcurrentframe(struct pt_regs *);
-
-/*
- * kdb_db_trap is a processor dependent routine invoked
- * from kdb() via the #db trap handler.   It handles breakpoints involving
- * the processor debug registers and handles single step traps
- * using the processor trace flag.
- */
-
-#define KDB_DB_BPT	0	/* Straight breakpoint */
-#define KDB_DB_SS	1	/* Single Step trap */
-#define KDB_DB_SSB	2	/* Single Step, caller should continue */
-
-extern int 	     kdb_db_trap(struct pt_regs *, int);
-
-extern int	     kdb_allocdbreg(kdb_bp_t *);
-extern void          kdb_freedbreg(kdb_bp_t *);
-extern void	     kdb_initdbregs(void);
-
-extern void          kdb_setsinglestep(struct pt_regs *);
-
-	/*
-	 *  Support for ia32 architecture debug registers.
-	 */
-#define KDB_DBREGS	4	
-extern k_machreg_t dbregs[];
-
-#define DR6_BT  0x00008000
-#define DR6_BS	0x00004000
-#define DR6_BD  0x00002000
-
-#define DR6_B3  0x00000008
-#define DR6_B2	0x00000004
-#define DR6_B1  0x00000002
-#define DR6_B0	0x00000001
-
-#define DR7_RW_VAL(dr, drnum) \
-       (((dr) >> (16 + (4 * (drnum)))) & 0x3)
-
-#define DR7_RW_SET(dr, drnum, rw)                              \
-       do {                                                    \
-               (dr) &= ~(0x3 << (16 + (4 * (drnum))));         \
-               (dr) |= (((rw) & 0x3) << (16 + (4 * (drnum)))); \
-       } while (0)
-
-#define DR7_RW0(dr)       DR7_RW_VAL(dr, 0)
-#define DR7_RW0SET(dr,rw)  DR7_RW_SET(dr, 0, rw)
-#define DR7_RW1(dr)       DR7_RW_VAL(dr, 1)
-#define DR7_RW1SET(dr,rw)  DR7_RW_SET(dr, 1, rw)
-#define DR7_RW2(dr)       DR7_RW_VAL(dr, 2)
-#define DR7_RW2SET(dr,rw)  DR7_RW_SET(dr, 2, rw)
-#define DR7_RW3(dr)       DR7_RW_VAL(dr, 3)
-#define DR7_RW3SET(dr,rw)  DR7_RW_SET(dr, 3, rw)
-
-
-#define DR7_LEN_VAL(dr, drnum) \
-       (((dr) >> (18 + (4 * (drnum)))) & 0x3)
-
-#define DR7_LEN_SET(dr, drnum, rw)                             \
-       do {                                                    \
-               (dr) &= ~(0x3 << (18 + (4 * (drnum))));         \
-               (dr) |= (((rw) & 0x3) << (18 + (4 * (drnum)))); \
-       } while (0)
-
-#define DR7_LEN0(dr)        DR7_LEN_VAL(dr, 0)
-#define DR7_LEN0SET(dr,len)  DR7_LEN_SET(dr, 0, len)
-#define DR7_LEN1(dr)        DR7_LEN_VAL(dr, 1)
-#define DR7_LEN1SET(dr,len)  DR7_LEN_SET(dr, 1, len)
-#define DR7_LEN2(dr)        DR7_LEN_VAL(dr, 2)
-#define DR7_LEN2SET(dr,len)  DR7_LEN_SET(dr, 2, len)
-#define DR7_LEN3(dr)        DR7_LEN_VAL(dr, 3)
-#define DR7_LEN3SET(dr,len)  DR7_LEN_SET(dr, 3, len)
-
-#define DR7_G0(dr)    (((dr)>>1)&0x1)
-#define DR7_G0SET(dr) ((dr) |= 0x2)
-#define DR7_G0CLR(dr) ((dr) &= ~0x2)
-#define DR7_G1(dr)    (((dr)>>3)&0x1)
-#define DR7_G1SET(dr) ((dr) |= 0x8)
-#define DR7_G1CLR(dr) ((dr) &= ~0x8)
-#define DR7_G2(dr)    (((dr)>>5)&0x1)
-#define DR7_G2SET(dr) ((dr) |= 0x20)
-#define DR7_G2CLR(dr) ((dr) &= ~0x20)
-#define DR7_G3(dr)    (((dr)>>7)&0x1)
-#define DR7_G3SET(dr) ((dr) |= 0x80)
-#define DR7_G3CLR(dr) ((dr) &= ~0x80)
-
-#define DR7_L0(dr)    (((dr))&0x1)
-#define DR7_L0SET(dr) ((dr) |= 0x1)
-#define DR7_L0CLR(dr) ((dr) &= ~0x1)
-#define DR7_L1(dr)    (((dr)>>2)&0x1)
-#define DR7_L1SET(dr) ((dr) |= 0x4)
-#define DR7_L1CLR(dr) ((dr) &= ~0x4)
-#define DR7_L2(dr)    (((dr)>>4)&0x1)
-#define DR7_L2SET(dr) ((dr) |= 0x10)
-#define DR7_L2CLR(dr) ((dr) &= ~0x10)
-#define DR7_L3(dr)    (((dr)>>6)&0x1)
-#define DR7_L3SET(dr) ((dr) |= 0x40)
-#define DR7_L3CLR(dr) ((dr) &= ~0x40)
-
-#define DR7_GD		0x00002000		/* General Detect Enable */
-#define DR7_GE		0x00000200		/* Global exact */
-#define DR7_LE		0x00000100		/* Local exact */
-
-extern k_machreg_t kdb_getdr6(void);
-extern void kdb_putdr6(k_machreg_t);
-
-extern k_machreg_t kdb_getdr7(void);
-extern void kdb_putdr7(k_machreg_t);
-
-extern k_machreg_t kdb_getdr(int);
-extern void kdb_putdr(int, k_machreg_t);
-
-extern k_machreg_t kdb_getcr(int);
-
-extern void kdb_bp_install(void);
-extern void kdb_bp_remove(void);
-
-/*
- * Support for setjmp/longjmp
- */
-#define JB_BX   0
-#define JB_SI   1
-#define JB_DI   2
-#define JB_BP   3
-#define JB_SP   4
-#define JB_PC   5
-
-typedef struct __kdb_jmp_buf {
-	unsigned long   regs[6];
-} kdb_jmp_buf;
-
-extern int kdb_setjmp(kdb_jmp_buf *);
-extern void kdb_longjmp(kdb_jmp_buf *, int);
-
-extern kdb_jmp_buf  kdbjmpbuf;
-
-#define getprsregs(regs)	((struct switch_stack *)regs -1)
-
-#define BITMASK(bp,value)  (value << bp)
-
-/* bkpt support using break inst instead of IBP reg */
-
-/*
- * Define certain specific instructions
- */
-#define BREAK_INSTR             (0x00000080100L << 11)
-#define INST_SLOT0_MASK         (0x1ffffffffffL << 5)
-
-#if 0
-#define MAX_BREAKPOINTS         40
-#define PSR_SS                  40
-#endif
-
-/**
- * IA-64 instruction format structures
- */
-typedef union bundle {
-        struct {
-                long    low8;
-                long    high8;
-        } lform;
-        struct {
-                int     low_low4;
-                int     low_high4;
-                long    high8;
-        } iform;
-} bundle_t;
-
-#define BKPTMODE_DATAR	3
-#define BKPTMODE_IO   	2
-#define BKPTMODE_DATAW	1
-#define BKPTMODE_INST	0
-
-/* Some of the fault registers needed by kdb but not passed with
- * regs or switch stack.
- */
-typedef struct fault_regs {
-	unsigned long	isr ;
-	unsigned long	ifa ;
-	unsigned long	iim ;
-	unsigned long	itir ;
-} fault_regs_t ;
-
-/*
- * State of kdb
- */
-
-typedef struct kdb_state {
-        int     cmd_given ;
-        int     reason_for_entry ;
-        int     bkpt_handling_state ;
-	int	kdb_action ;
-} kdb_state_t ;
-
-#define BKPTSTATE_NOT_HANDLED 	0
-#define BKPTSTATE_HANDLED 	1
-
-#define CMDGIVEN_UNKNOWN	0	
-#define CMDGIVEN_SSTEP		1	
-#define CMDGIVEN_GO		2	
-
-#define ENTRYREASON_GO	 	0
-#define ENTRYREASON_SSTEP	1
-
-#define ACTION_UNKNOWN		0
-#define ACTION_NOBPINSTALL	1
-#define ACTION_NOPROMPT		2
-
-#endif /* _ASM_IA64_KDBSUPPORT_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/keyboard.h linux/include/asm-ia64/keyboard.h
--- v2.3.99-pre5/linux/include/asm-ia64/keyboard.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/keyboard.h	Fri Apr 21 16:38:40 2000
@@ -11,7 +11,7 @@
 
 # ifdef __KERNEL__
 
-#include <linux/config.h>
+#include <linux/irq.h>
 
 #define KEYBOARD_IRQ			isa_irq_to_vector(1)
 #define DISABLE_KBD_DURING_INTERRUPTS	0
@@ -38,9 +38,6 @@
 #define INIT_KBD
 
 #define SYSRQ_KEY		0x54
-#if defined(CONFIG_KDB)
-#define E1_PAUSE  119                   /* PAUSE key */
-#endif
 
 /* resource allocation */
 #define kbd_request_region()
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/mca.h linux/include/asm-ia64/mca.h
--- v2.3.99-pre5/linux/include/asm-ia64/mca.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/mca.h	Fri Apr 21 15:21:24 2000
@@ -6,9 +6,14 @@
  * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
  * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
  */
+
+/* XXX use this temporary define for MP systems trying to INIT */
+#define SAL_MPINIT_WORKAROUND
+
 #ifndef _ASM_IA64_MCA_H
 #define _ASM_IA64_MCA_H
 
+#if !defined(__ASSEMBLY__)
 #include <linux/types.h>
 #include <asm/param.h>
 #include <asm/sal.h>
@@ -119,7 +124,7 @@
 
 typedef int (*prfunc_t)(const char * fmt, ...);
 
-extern void mca_init(void);
+extern void ia64_mca_init(void);
 extern void ia64_os_mca_dispatch(void);
 extern void ia64_os_mca_dispatch_end(void);
 extern void ia64_mca_ucmc_handler(void);
@@ -134,10 +139,12 @@
 
 #undef 	MCA_TEST
 
-#if defined(MCA_TEST)
-# define MCA_DEBUG	printk
+#define IA64_MCA_DEBUG_INFO 1
+
+#if defined(IA64_MCA_DEBUG_INFO)
+# define IA64_MCA_DEBUG	printk
 #else
-# define MCA_DEBUG
+# define IA64_MCA_DEBUG
 #endif
-
+#endif /* !__ASSEMBLY__ */
 #endif /* _ASM_IA64_MCA_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/mca_asm.h linux/include/asm-ia64/mca_asm.h
--- v2.3.99-pre5/linux/include/asm-ia64/mca_asm.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/mca_asm.h	Fri Apr 21 15:21:24 2000
@@ -3,7 +3,9 @@
  *
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
- * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
+ * Copyright (C) 2000 Hewlett-Packard Co.
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #ifndef _ASM_IA64_MCA_ASM_H
 #define _ASM_IA64_MCA_ASM_H
@@ -70,25 +72,26 @@
 	;;										\
 	dep	old_psr = 0, old_psr, 32, 32;						\
 	                                                                                \
-	mov	ar##.##rsc = r0 ;							\
+	mov	ar.rsc = r0 ;								\
 	;;										\
-	mov	temp2 = ar##.##bspstore;						\
+	mov	temp2 = ar.bspstore;							\
 	;;										\
 	DATA_VA_TO_PA(temp2);								\
 	;;										\
-	mov	temp1 = ar##.##rnat;							\
+	mov	temp1 = ar.rnat;							\
 	;;										\
-	mov	ar##.##bspstore = temp2;						\
+	mov	ar.bspstore = temp2;							\
 	;;										\
-	mov	ar##.##rnat = temp1;							\
+	mov	ar.rnat = temp1;							\
 	mov	temp1 = psr;								\
 	mov	temp2 = psr;								\
 	;;										\
 	                                                                                \
 	dep	temp2 = 0, temp2, PSR_IC, 2;						\
 	;;										\
-	mov	psr##.##l = temp2;							\
-	                                                                                \
+	mov	psr.l = temp2;								\
+	;;										\
+	srlz.d;										\
 	dep	temp1 = 0, temp1, 32, 32;						\
 	;;										\
  	dep	temp1 = 0, temp1, PSR_IT, 1;						\
@@ -100,15 +103,16 @@
 	dep	temp1 = 0, temp1, PSR_I, 1;						\
 	;;										\
 	movl	temp2 = start_addr;							\
-	mov	cr##.##ipsr = temp1;							\
+	mov	cr.ipsr = temp1;							\
 	;;										\
 	INST_VA_TO_PA(temp2);								\
-	mov	cr##.##iip = temp2;							\
-	mov	cr##.##ifs = r0;							\
+	;;										\
+	mov	cr.iip = temp2;								\
+	mov	cr.ifs = r0;								\
 	DATA_VA_TO_PA(sp)								\
 	DATA_VA_TO_PA(gp)								\
 	;;										\
-	srlz##.##i;									\
+	srlz.i;										\
 	;;										\
 	nop	1;									\
 	nop	2;									\
@@ -143,18 +147,19 @@
 	;;										\
 	dep	temp2 = 0, temp2, PSR_IC, 2;						\
 	;;										\
-	mov	psr##.##l = temp2;							\
-	mov	ar##.##rsc = r0 ;							\
+	mov	psr.l = temp2;								\
+	mov	ar.rsc = r0;								\
 	;;										\
-	mov	temp2 = ar##.##bspstore;						\
+	srlz.d;										\
+	mov	temp2 = ar.bspstore;							\
 	;;										\
 	DATA_PA_TO_VA(temp2,temp1);							\
 	;;										\
-	mov	temp1 = ar##.##rnat;							\
+	mov	temp1 = ar.rnat;							\
 	;;										\
-	mov	ar##.##bspstore = temp2;						\
+	mov	ar.bspstore = temp2;							\
 	;;										\
-	mov	ar##.##rnat = temp1;							\
+	mov	ar.rnat = temp1;							\
 	;;										\
 	mov	temp1 = old_psr;							\
 	;;										\
@@ -172,12 +177,12 @@
 	dep	temp1 = temp2, temp1, PSR_BN, 1;					\
 	;;										\
 	                                                                                \
-	mov     cr##.##ipsr = temp1;							\
+	mov     cr.ipsr = temp1;							\
 	movl	temp2 = start_addr;							\
 	;;										\
-	mov	cr##.##iip = temp2;							\
+	mov	cr.iip = temp2;								\
 	DATA_PA_TO_VA(sp, temp1);							\
-	DATA_PA_TO_VA(gp, temp1);							\
+	DATA_PA_TO_VA(gp, temp2);							\
 	;;										\
 	nop	1;									\
 	nop	2;									\
@@ -226,19 +231,19 @@
  */
 #define rse_switch_context(temp,p_stackframe,p_bspstore) 			\
         ;; 									\
-        mov     temp=ar##.##rsc;; 						\
+        mov     temp=ar.rsc;; 							\
         st8     [p_stackframe]=temp,8;; 					\
-        mov     temp=ar##.##pfs;; 						\
+        mov     temp=ar.pfs;; 							\
         st8     [p_stackframe]=temp,8; 						\
         cover ;;								\
-        mov     temp=cr##.##ifs;; 						\
+        mov     temp=cr.ifs;; 							\
         st8     [p_stackframe]=temp,8;;	 					\
-        mov     temp=ar##.##bspstore;; 						\
+        mov     temp=ar.bspstore;; 						\
         st8     [p_stackframe]=temp,8;; 					\
-        mov     temp=ar##.##rnat;; 						\
+        mov     temp=ar.rnat;; 							\
         st8     [p_stackframe]=temp,8; 						\
-        mov     ar##.##bspstore=p_bspstore;; 					\
-        mov     temp=ar##.##bsp;; 						\
+        mov     ar.bspstore=p_bspstore;; 					\
+        mov     temp=ar.bsp;; 							\
         sub     temp=temp,p_bspstore;;						\
         st8     [p_stackframe]=temp,8
 
@@ -262,23 +267,23 @@
         add     p_stackframe=rse_ndirty_offset,p_stackframe;;			\
         ld8     temp=[p_stackframe];; 						\
         shl     temp=temp,16;;							\
-        mov     ar##.##rsc=temp;; 						\
+        mov     ar.rsc=temp;; 							\
         loadrs;;								\
         add     p_stackframe=-rse_ndirty_offset+rse_bspstore_offset,p_stackframe;;\
         ld8     temp=[p_stackframe];; 						\
-        mov     ar##.##bspstore=temp;; 						\
+        mov     ar.bspstore=temp;; 						\
         add     p_stackframe=-rse_bspstore_offset+rse_rnat_offset,p_stackframe;;\
         ld8     temp=[p_stackframe];; 						\
-        mov     ar##.##rnat=temp;;						\
+        mov     ar.rnat=temp;;							\
         add     p_stackframe=-rse_rnat_offset+rse_pfs_offset,p_stackframe;;	\
         ld8     temp=[p_stackframe];; 						\
-        mov     ar##.##pfs=temp;						\
+        mov     ar.pfs=temp;							\
         add     p_stackframe=-rse_pfs_offset+rse_ifs_offset,p_stackframe;;	\
         ld8     temp=[p_stackframe];; 						\
-        mov     cr##.##ifs=temp;						\
+        mov     cr.ifs=temp;							\
         add     p_stackframe=-rse_ifs_offset+rse_rsc_offset,p_stackframe;;	\
         ld8     temp=[p_stackframe];; 						\
-        mov     ar##.##rsc=temp ;						\
+        mov     ar.rsc=temp ;							\
         add     p_stackframe=-rse_rsc_offset,p_stackframe;			\
         mov     temp=cr.ipsr;;							\
         st8     [p_stackframe]=temp,8;						\
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/mman.h linux/include/asm-ia64/mman.h
--- v2.3.99-pre5/linux/include/asm-ia64/mman.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/mman.h	Fri Apr 21 15:21:24 2000
@@ -2,8 +2,8 @@
 #define _ASM_IA64_MMAN_H
 
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #define PROT_READ	0x1		/* page can be read */
@@ -30,6 +30,12 @@
 
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
+
+#define MADV_NORMAL	0x0		/* default page-in behavior */
+#define MADV_RANDOM	0x1		/* page-in minimum required */
+#define MADV_SEQUENTIAL	0x2		/* read-ahead aggressively */
+#define MADV_WILLNEED	0x3		/* pre-fault pages */
+#define MADV_DONTNEED	0x4		/* discard these pages */
 
 /* compatibility flags */
 #define MAP_ANON	MAP_ANONYMOUS
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/offsets.h linux/include/asm-ia64/offsets.h
--- v2.3.99-pre5/linux/include/asm-ia64/offsets.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-ia64/offsets.h	Fri Apr 21 15:21:24 2000
@@ -10,7 +10,7 @@
 
 #define PF_PTRACED_BIT			4
 
-#define IA64_TASK_SIZE			2800	/* 0xaf0 */
+#define IA64_TASK_SIZE			2816	/* 0xb00 */
 #define IA64_PT_REGS_SIZE		400	/* 0x190 */
 #define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
 #define IA64_SIGINFO_SIZE		136	/* 0x88 */
@@ -21,6 +21,7 @@
 #define IA64_TASK_PROCESSOR_OFFSET	108	/* 0x6c */
 #define IA64_TASK_THREAD_OFFSET		928	/* 0x3a0 */
 #define IA64_TASK_THREAD_KSP_OFFSET	928	/* 0x3a0 */
+#define IA64_TASK_THREAD_SIGMASK_OFFSET	2656	/* 0xa60 */
 #define IA64_TASK_PID_OFFSET		188	/* 0xbc */
 #define IA64_TASK_MM_OFFSET		88	/* 0x58 */
 #define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
@@ -34,5 +35,7 @@
 #define IA64_SIGCONTEXT_FLAGS_OFFSET	0	/* 0x0 */
 #define IA64_SIGCONTEXT_CFM_OFFSET	48	/* 0x30 */
 #define IA64_SIGCONTEXT_FR6_OFFSET	560	/* 0x230 */
+#define IA64_CLONE_VFORK			16384	/* 0x4000 */
+#define IA64_CLONE_VM			256	/* 0x100 */
 
 #endif /* _ASM_IA64_OFFSETS_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/pal.h linux/include/asm-ia64/pal.h
--- v2.3.99-pre5/linux/include/asm-ia64/pal.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/pal.h	Fri Apr 21 15:21:24 2000
@@ -15,6 +15,7 @@
  *
  * 99/10/01	davidm	Make sure we pass zero for reserved parameters.
  * 00/03/07	davidm	Updated pal_cache_flush() to be in sync with PAL v2.6.
+ * 00/03/23     cfleck  Modified processor min-state save area to match updated PAL & SAL info
  */
 
 /*
@@ -595,18 +596,27 @@
 #define pmci_bus_external_error			pme_bus.eb
 #define pmci_bus_mc				pme_bus.mc
 
+/* 
+ * NOTE: this min_state_save area struct only includes the 1KB 
+ * architectural state save area.  The other 3 KB is scratch space
+ * for PAL.
+ */
 
 typedef struct pal_min_state_area_s {
-	u64	pmsa_reserved[26];
-	u64	pmsa_xfs;
-	u64	pmsa_xpsr;
-	u64	pmsa_xip;
-	u64	pmsa_rsc;
-	u64	pmsa_br0;
-	u64	pmsa_pr;
-	u64	pmsa_bank0_gr[16];
-	u64	pmsa_gr[16];
-	u64	pmsa_nat_bits;
+	u64	pmsa_nat_bits;		/* nat bits for saved GRs  */
+	u64	pmsa_gr[15];		/* GR1	- GR15		   */
+	u64	pmsa_bank0_gr[16];	/* GR16 - GR31		   */
+	u64	pmsa_bank1_gr[16];	/* GR16 - GR31		   */
+	u64	pmsa_pr;		/* predicate registers	   */
+	u64	pmsa_br0;		/* branch register 0	   */
+	u64	pmsa_rsc;		/* ar.rsc		   */
+	u64	pmsa_iip;		/* cr.iip		   */
+	u64	pmsa_ipsr;		/* cr.ipsr		   */
+	u64	pmsa_ifs;		/* cr.ifs		   */
+	u64	pmsa_xip;		/* previous iip		   */
+	u64	pmsa_xpsr;		/* previous psr		   */
+	u64	pmsa_xfs;		/* previous ifs		   */
+	u64	pmsa_reserved[71];	/* pal_min_state_area should total to 1KB */
 } pal_min_state_area_t;
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/pgalloc.h linux/include/asm-ia64/pgalloc.h
--- v2.3.99-pre5/linux/include/asm-ia64/pgalloc.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-ia64/pgalloc.h	Fri Apr 21 15:21:24 2000
@@ -139,6 +139,9 @@
 #define pmd_free(pmd)		free_pmd_fast(pmd)
 #define pgd_free(pgd)		free_pgd_fast(pgd)
 
+extern void __handle_bad_pgd (pgd_t *pgd);
+extern void __handle_bad_pmd (pmd_t *pmd);
+
 extern __inline__ pte_t*
 pte_alloc (pmd_t *pmd, unsigned long vmaddr)
 {
@@ -242,11 +245,6 @@
 
 /*
  * Page-granular tlb flush.
- *
- * do a tbisd (type = 2) normally, and a tbis (type = 3)
- * if it is an executable mapping.  We want to avoid the
- * itlb flush, because that potentially also does a
- * icache flush.
  */
 static __inline__ void
 flush_tlb_page (struct vm_area_struct *vma, unsigned long addr)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/pgtable.h linux/include/asm-ia64/pgtable.h
--- v2.3.99-pre5/linux/include/asm-ia64/pgtable.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/pgtable.h	Fri Apr 21 16:38:55 2000
@@ -8,16 +8,24 @@
  * This hopefully works with any (fixed) ia-64 page-size, as defined
  * in <asm/page.h> (currently 8192).
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
+#include <linux/config.h>
+
 #include <asm/mman.h>
 #include <asm/page.h>
 #include <asm/types.h>
 
-/* Size of physical address space: */
-#define IA64_PHYS_BITS		50		/* EAS2.5 defines 50 bits of ppn */
+/* Size of virtuaql and physical address spaces: */
+#ifdef CONFIG_ITANIUM
+# define IA64_IMPL_VA_MSB	50
+# define IA64_PHYS_BITS		44		/* Itanium PRM defines 44 bits of ppn */
+#else
+# define IA64_IMPL_VA_MSB	60		/* maximum value (bits 61-63 are region bits) */
+# define IA64_PHYS_BITS		50		/* EAS2.6 allows up to 50 bits of ppn */
+#endif
 #define IA64_PHYS_SIZE		(__IA64_UL(1) << IA64_PHYS_BITS)
 
 /* Is ADDR a valid kernel address? */
@@ -336,10 +344,6 @@
 /* Find an entry in the third-level page table.. */
 #define pte_offset(dir,addr) \
 	((pte_t *) pmd_page(*(dir)) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
-
-
-extern void __handle_bad_pgd (pgd_t *pgd);
-extern void __handle_bad_pmd (pmd_t *pmd);
 
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h
--- v2.3.99-pre5/linux/include/asm-ia64/processor.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-ia64/processor.h	Fri Apr 21 15:21:24 2000
@@ -62,6 +62,8 @@
 #define IA64_PSR_TB_BIT		26
 #define IA64_PSR_RT_BIT		27
 /* The following are not affected by save_flags()/restore_flags(): */
+#define IA64_PSR_CPL0_BIT	32
+#define IA64_PSR_CPL1_BIT	33
 #define IA64_PSR_IS_BIT		34
 #define IA64_PSR_MC_BIT		35
 #define IA64_PSR_IT_BIT		36
@@ -151,6 +153,7 @@
 #define IA64_THREAD_DBG_VALID	(__IA64_UL(1) << 1)	/* debug registers valid? */
 #define IA64_THREAD_UAC_NOPRINT	(__IA64_UL(1) << 2)	/* don't log unaligned accesses */
 #define IA64_THREAD_UAC_SIGBUS	(__IA64_UL(1) << 3)	/* generate SIGBUS on unaligned acc. */
+#define IA64_THREAD_KRBS_SYNCED	(__IA64_UL(1) << 4)	/* krbs synced with process vm? */
 #define IA64_KERNEL_DEATH	(__IA64_UL(1) << 63)	/* see die_if_kernel()... */
 
 #define IA64_THREAD_UAC_SHIFT	2	
@@ -270,6 +273,8 @@
 		 (int *) (addr));								\
 })
 
+struct siginfo;
+
 struct thread_struct {
 	__u64 ksp;			/* kernel stack pointer */
 	unsigned long flags;		/* various flags */
@@ -278,14 +283,19 @@
 	__u64 ibr[IA64_NUM_DBG_REGS];
 	__u64 map_base;			/* base address for mmap() */
 #ifdef CONFIG_IA32_SUPPORT
+	__u64 eflag;			/* IA32 EFLAGS reg */
 	__u64 fsr;			/* IA32 floating pt status reg */
 	__u64 fcr;			/* IA32 floating pt control reg */
 	__u64 fir;			/* IA32 fp except. instr. reg */
 	__u64 fdr;			/* IA32 fp except. data reg */
-# define INIT_THREAD_IA32	, 0, 0, 0, 0
+	union {
+		__u64 sigmask;		/* aligned mask for sigsuspend scall */
+	} un;
+# define INIT_THREAD_IA32	, 0, 0, 0, 0, 0, {0}
 #else
 # define INIT_THREAD_IA32
 #endif /* CONFIG_IA32_SUPPORT */
+	struct siginfo *siginfo;	/* current siginfo struct for ptrace() */
 };
 
 #define INIT_MMAP {								\
@@ -300,7 +310,8 @@
 	{0, },				/* dbr */	\
 	{0, },				/* ibr */	\
 	0x2000000000000000		/* map_base */	\
-	INIT_THREAD_IA32				\
+	INIT_THREAD_IA32,				\
+	0				/* siginfo */	\
 }
 
 #define start_thread(regs,new_ip,new_sp) do {					\
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/ptrace.h linux/include/asm-ia64/ptrace.h
--- v2.3.99-pre5/linux/include/asm-ia64/ptrace.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-ia64/ptrace.h	Fri Apr 21 15:21:24 2000
@@ -232,9 +232,11 @@
 #endif /* !__ASSEMBLY__ */
 
 /*
- * The number chosen here is somewhat arbitrary but absolutely MUST
+ * The numbers chosen here are somewhat arbitrary but absolutely MUST
  * not overlap with any of the number assigned in <linux/ptrace.h>.
  */
 #define PTRACE_SINGLEBLOCK	12	/* resume execution until next branch */
+#define PTRACE_GETSIGINFO	13	/* get child's siginfo structure */
+#define PTRACE_SETSIGINFO	14	/* set child's siginfo structure */
 
 #endif /* _ASM_IA64_PTRACE_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/ptrace_offsets.h linux/include/asm-ia64/ptrace_offsets.h
--- v2.3.99-pre5/linux/include/asm-ia64/ptrace_offsets.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/ptrace_offsets.h	Fri Apr 21 15:21:24 2000
@@ -13,9 +13,9 @@
  *		struct ia64_fpreg fph[96];		// f32-f127
  *		struct switch_stack sw;
  *		struct pt_regs pt;
- *		unsigned long rsvd1[358];
+ *		unsigned long rsvd1[712];
  *		unsigned long dbr[8];
- *		unsigned long rsvd2[252];
+ *		unsigned long rsvd2[504];
  *		unsigned long ibr[8];
  *	}
  */
@@ -165,7 +165,8 @@
 /* pt_regs */
 #define PT_CR_IPSR		0x0830
 #define PT_CR_IIP		0x0838
-#define PT_CR_IFS		0x0840
+#define PT_CFM			0x0840
+#define PT_CR_IFS		PT_CFM		/* Use of PT_CR_IFS is deprecated */
 #define PT_AR_UNAT		0x0848
 #define PT_AR_PFS		0x0850
 #define PT_AR_RSC		0x0858
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/sal.h linux/include/asm-ia64/sal.h
--- v2.3.99-pre5/linux/include/asm-ia64/sal.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/sal.h	Fri Apr 21 15:21:24 2000
@@ -12,6 +12,8 @@
  * Copyright (C) 1999 Srinivasa Prasad Thirumalachar <sprasad@sprasad.engr.sgi.com>
  *
  * 99/09/29 davidm	Updated for SAL 2.6.
+ * 00/03/29 cfleck      Updated SAL Error Logging info for processor (SAL 2.6) 
+ *                      (plus examples of platform error info structures from smariset @ Intel)
  */
 
 #include <linux/config.h>
@@ -274,8 +276,6 @@
 	} slpi_bus_check_info[MAX_BUS_ERRORS];
 
 	pal_min_state_area_t		slpi_min_state_area;
-	u64				slpi_bank1_gr[16];
-	u64				slpi_bank1_nat_bits;
 	u64				slpi_br[8];
 	u64				slpi_cr[128];
 	u64				slpi_ar[128];
@@ -283,6 +283,87 @@
 	u64				slpi_fr[128];
 } sal_log_processor_info_t;
 
+/* platform error log structures */
+typedef struct platerr_logheader {
+	u64	nextlog;	/* next log offset if present */
+	u64	loglength;	/* log length */
+	u64	logsubtype;	/* log subtype memory/bus/component */
+	u64	eseverity;	/* error severity */
+} ehdr_t;
+
+typedef struct sysmem_errlog {
+	ehdr_t	lhdr;		/* header */
+	u64	vflag;		/* valid bits for each field in the log */
+	u64	addr;		/* memory address */
+	u64	data;		/* memory data */
+	u64	cmd;		/* command bus value if any */
+	u64	ctrl;		/* control bus value if any */
+	u64	addrsyndrome;	/* memory address ecc/parity syndrome bits */
+	u64	datasyndrome;	/* data ecc/parity syndrome */
+	u64	cacheinfo;	/* platform cache info as defined in pal spec. table 7-34 */
+} merrlog_t;
+
+typedef struct sysbus_errlog {
+	ehdr_t	lhdr;		/* linkded list header */
+	u64	vflag;		/* valid bits for each field in the log */
+	u64	busnum;		/* bus number in error */
+	u64	reqaddr;	/* requestor address */
+	u64	resaddr;	/* responder address */
+	u64	taraddr;	/* target address */
+	u64	data;		/* requester r/w data */
+	u64	cmd;		/* bus commands */
+	u64	ctrl;		/* bus controls (be# &-0) */
+	u64	addrsyndrome;	/* addr bus ecc/parity bits */
+	u64	datasyndrome;	/* data bus ecc/parity bits */
+	u64	cmdsyndrome;	/* command bus ecc/parity bits */
+	u64	ctrlsyndrome;	/* control bus ecc/parity bits */
+} berrlog_t;
+
+/* platform error log structures */
+typedef struct syserr_chdr {	/* one header per component */
+	u64	busnum;		/* bus number on which the component resides */
+	u64	devnum;		/* same as device select */
+	u64	funcid;		/* function id of the device */
+	u64	devid;		/* pci device id */
+	u64	classcode;	/* pci class code for the device */
+	u64	cmdreg;		/* pci command reg value */
+	u64	statreg;	/* pci status reg value */
+} chdr_t;
+
+typedef struct cfginfo {
+	u64	cfgaddr;
+	u64	cfgval;
+} cfginfo_t;
+
+typedef struct sys_comperr {	/* per component */
+	ehdr_t	lhdr;		/* linked list header */
+	u64	vflag;		/* valid bits for each field in the log */
+	chdr_t	scomphdr;	
+	u64	numregpair;	/* number of reg addr/value pairs */
+	cfginfo_t cfginfo;
+} cerrlog_t;
+
+typedef struct sel_records {
+	ehdr_t	lhdr;
+	u64	seldata;
+} isel_t;
+
+typedef struct plat_errlog {
+	u64	      mbcsvalid;	/* valid bits for each type of log */
+	merrlog_t     smemerrlog;	/* platform memory error logs */
+	berrlog_t     sbuserrlog;	/* platform bus error logs */
+	cerrlog_t     scomperrlog;	/* platform chipset error logs */
+	isel_t	      selrecord;	/* ipmi sel record */
+} platforminfo_t;
+
+/* over all log structure (processor+platform) */
+
+typedef union udev_specific_log {
+	sal_log_processor_info_t  proclog;
+	platforminfo_t		  platlog;
+} devicelog_t;
+
+
 #define sal_log_processor_info_psi_valid		slpi_valid.spli_psi
 #define sal_log_processor_info_cache_check_valid	slpi_valid.spli_cache_check
 #define sal_log_processor_info_tlb_check_valid		slpi_valid.spli_tlb_check
@@ -303,15 +384,14 @@
 	ushort			slh_log_type;		/* Type of log (0 - cpu ,1 - platform) */
 	ushort			slh_log_sub_type;	/* SGI specific sub type */
 	sal_log_timestamp_t	slh_log_timestamp;	/* Timestamp */
-	u64			slh_log_dev_spec_info;	/* For processor log this field will
-							 * contain an area architected for all
-							 * IA-64 processors. For platform log
-							 * this field will contain information
-							 * specific to the hardware 
-							 * implementation.
-							 */
 } sal_log_header_t;
 
+/* SAL PSI log structure */
+typedef struct psilog
+{
+	sal_log_header_t   sal_elog_header;
+	devicelog_t        devlog;
+} ia64_psilog_t;
 
 /*
  * Now define a couple of inline functions for improved type checking
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/semaphore.h linux/include/asm-ia64/semaphore.h
--- v2.3.99-pre5/linux/include/asm-ia64/semaphore.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-ia64/semaphore.h	Fri Apr 21 15:21:24 2000
@@ -230,7 +230,7 @@
 	do {
 		old_count = sem->count;
 		new_count = old_count - RW_LOCK_BIAS;
-	} while (cmpxchg(&sem->count, old_count, new_count) != old_count);
+	} while (cmpxchg_acq(&sem->count, old_count, new_count) != old_count);
 
 	if (new_count != 0)
 		__down_write_failed(sem, new_count);
@@ -279,7 +279,7 @@
 	do {
 		old_count = sem->count;
 		new_count = old_count + RW_LOCK_BIAS;
-	} while (cmpxchg(&sem->count, old_count, new_count) != old_count);
+	} while (cmpxchg_rel(&sem->count, old_count, new_count) != old_count);
 
 	/*
 	 * Note: new_count <u RW_LOCK_BIAS <=> old_count < 0 && new_count >= 0.
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/siginfo.h linux/include/asm-ia64/siginfo.h
--- v2.3.99-pre5/linux/include/asm-ia64/siginfo.h	Sat Feb 26 22:31:55 2000
+++ linux/include/asm-ia64/siginfo.h	Fri Apr 21 15:21:24 2000
@@ -152,7 +152,8 @@
 #define TRAP_BRKPT	1	/* process breakpoint */
 #define TRAP_TRACE	2	/* process trace trap */
 #define TRAP_BRANCH	3	/* process taken branch trap */
-#define NSIGTRAP	3
+#define TRAP_HWBKPT	4	/* hardware breakpoint or watchpoint */
+#define NSIGTRAP	4
 
 /*
  * SIGCHLD si_codes
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/smp.h linux/include/asm-ia64/smp.h
--- v2.3.99-pre5/linux/include/asm-ia64/smp.h	Fri Mar 10 16:40:49 2000
+++ linux/include/asm-ia64/smp.h	Fri Apr 21 15:21:24 2000
@@ -18,10 +18,17 @@
 #include <asm/ptrace.h>
 #include <asm/io.h>
 
-#define IPI_DEFAULT_BASE_ADDR	0xfee00000
 #define XTP_OFFSET		0x1e0008
 
-#define smp_processor_id() (current->processor)
+#define SMP_IRQ_REDIRECTION     (1 << 0)
+#define SMP_IPI_REDIRECTION     (1 << 1)
+
+#define smp_processor_id()	(current->processor)
+
+struct smp_boot_data {
+	int cpu_count;
+	int cpu_map[NR_CPUS];
+};
 
 extern unsigned long cpu_present_map;
 extern unsigned long cpu_online_map;
@@ -29,52 +36,43 @@
 extern int bootstrap_processor;
 extern volatile int __cpu_number_map[NR_CPUS];
 extern volatile int __cpu_logical_map[NR_CPUS];
+extern unsigned char smp_int_redirect;
+extern char no_int_routing;
 
 #define cpu_number_map(i)	__cpu_number_map[i]
 #define cpu_logical_map(i)	__cpu_logical_map[i]
 
-#if defined(CONFIG_KDB)
-extern volatile unsigned long smp_kdb_wait;
-#endif  /* CONFIG_KDB */
-
 extern unsigned long ap_wakeup_vector;
 
 /*
  * XTP control functions:
  *    min_xtp   :  route all interrupts to this CPU
  *    normal_xtp:  nominal XTP value
- *    raise_xtp :  Route all interrupts away from this CPU
  *    max_xtp   :  never deliver interrupts to this CPU.
  */
 
-/* 
- * This turns off XTP based interrupt routing.  There is a bug in the handling of 
- * IRQ_INPROGRESS when the same vector appears on more than one CPU. 
- */
-extern int use_xtp;
-
 extern __inline void 
 min_xtp(void)
 {
-	if (use_xtp)
-		writeb(0x80, ipi_base_addr | XTP_OFFSET); /* XTP to min */
+	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
+		writeb(0x00, ipi_base_addr | XTP_OFFSET); /* XTP to min */
 }
 
 extern __inline void
 normal_xtp(void)
 {
-	if (use_xtp)
-		writeb(0x8e, ipi_base_addr | XTP_OFFSET); /* XTP normal */
+	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
+		writeb(0x08, ipi_base_addr | XTP_OFFSET); /* XTP normal */
 }
 
 extern __inline void
 max_xtp(void) 
 {
-	if (use_xtp)
-		writeb(0x8f, ipi_base_addr | XTP_OFFSET); /* Set XTP to max... */
+	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
+		writeb(0x0f, ipi_base_addr | XTP_OFFSET); /* Set XTP to max */
 }
 
-extern __inline unsigned int 
+extern __inline__ unsigned int 
 hard_smp_processor_id(void)
 {
 	struct {
@@ -84,18 +82,19 @@
 		unsigned long ignored : 32;
 	} lid;
 
-	__asm__ __volatile__ ("mov %0=cr.lid" : "=r" (lid));
+	__asm__ ("mov %0=cr.lid" : "=r" (lid));
 
-	/*
-	 * Damn.  IA64 CPU ID's are 16 bits long, Linux expect the hard id to be 
-	 * in the range 0..31.  So, return the low-order bits of the bus-local ID 
-	 * only and hope it's less than 32. This needs to be fixed...
-	 */
-	return (lid.id & 0x0f);
+#ifdef LARGE_CPU_ID_OK
+	return lid.eid << 8 | lid.id;
+#else
+	if (((lid.id << 8) | lid.eid) > NR_CPUS)
+		printk("WARNING: SMP ID %d > NR_CPUS\n", (lid.id << 8) | lid.eid);
+	return lid.id;
+#endif
 }
 
-#define NO_PROC_ID 0xffffffff
-#define PROC_CHANGE_PENALTY 20
+#define NO_PROC_ID		(-1)
+#define PROC_CHANGE_PENALTY	20
 
 extern void __init init_smp_config (void);
 extern void smp_do_timer (struct pt_regs *regs);
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/spinlock.h linux/include/asm-ia64/spinlock.h
--- v2.3.99-pre5/linux/include/asm-ia64/spinlock.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/spinlock.h	Fri Apr 21 15:21:24 2000
@@ -2,8 +2,8 @@
 #define _ASM_IA64_SPINLOCK_H
 
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  *
  * This file is used for SMP configurations only.
@@ -16,29 +16,58 @@
 typedef struct { 
 	volatile unsigned int lock;
 } spinlock_t;
+
 #define SPIN_LOCK_UNLOCKED			(spinlock_t) { 0 }
 #define spin_lock_init(x)			((x)->lock = 0) 
 
-/* Streamlined test_and_set_bit(0, (x)) */
+/*
+ * Streamlined test_and_set_bit(0, (x)).  We use test-and-test-and-set
+ * rather than a simple xchg to avoid writing the cache-line when
+ * there is contention.
+ */
+#if 1 /* Bad code generation? */
 #define spin_lock(x) __asm__ __volatile__ ( \
-	"mov ar.ccv = r0\n" \
-	"mov r29 = 1\n" \
-	";;\n" \
-	"1:\n" \
-	"ld4 r2 = [%0]\n" \
-	";;\n" \
-	"cmp4.eq p0,p7 = r0,r2\n" \
-	"(p7) br.cond.dptk.few 1b \n" \
-	"cmpxchg4.acq r2 = [%0], r29, ar.ccv\n" \
-	";;\n" \
-	"cmp4.eq p0,p7 = r0, r2\n" \
-	"(p7) br.cond.dptk.few 1b\n" \
-	";;\n" \
-	:: "m" __atomic_fool_gcc((x)) : "r2", "r29")
-
-#define spin_unlock(x) __asm__ __volatile__ ("st4.rel [%0] = r0;;" : "=m" (__atomic_fool_gcc((x))))
-
-#define spin_trylock(x) (!test_and_set_bit(0, (x)))
+       "mov ar.ccv = r0\n" \
+       "mov r29 = 1\n" \
+       ";;\n" \
+       "1:\n" \
+       "ld4 r2 = %0\n" \
+       ";;\n" \
+       "cmp4.eq p0,p7 = r0,r2\n" \
+       "(p7) br.cond.spnt.few 1b \n" \
+       "cmpxchg4.acq r2 = %0, r29, ar.ccv\n" \
+       ";;\n" \
+       "cmp4.eq p0,p7 = r0, r2\n" \
+       "(p7) br.cond.spnt.few 1b\n" \
+       ";;\n" \
+       :: "m" __atomic_fool_gcc((x)) : "r2", "r29")
+ 
+#else 
+#define spin_lock(x)					\
+{							\
+	spinlock_t *__x = (x);				\
+							\
+	do {						\
+		while (__x->lock);			\
+	} while (cmpxchg_acq(&__x->lock, 0, 1));	\
+}
+#endif
+
+#define spin_is_locked(x)	((x)->lock != 0)
+
+#define spin_unlock(x)		(((spinlock_t *) x)->lock = 0)
+
+/* Streamlined !test_and_set_bit(0, (x)) */
+#define spin_trylock(x)						\
+({								\
+	spinlock_t *__x = (x);					\
+	__u32 old;						\
+								\
+	do {							\
+		old = __x->lock;				\
+	} while (cmpxchg_acq(&__x->lock, old, 1) != old);	\
+	old == 0;						\
+})
 
 #define spin_unlock_wait(x) \
 	({ do { barrier(); } while(((volatile spinlock_t *)x)->lock); })
@@ -49,47 +78,43 @@
 } rwlock_t;
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
-#define read_lock(rw) \
-do { \
-	int tmp = 0; \
-	__asm__ __volatile__ ("1:\tfetchadd4.acq %0 = %1, 1\n" \
-			      ";;\n" \
-			      "tbit.nz p6,p0 = %0, 31\n" \
-			      "(p6) br.cond.sptk.few 2f\n" \
-			      ".section .text.lock,\"ax\"\n" \
-			      "2:\tfetchadd4.rel %0 = %1, -1\n" \
-			      ";;\n" \
-			      "3:\tld4.acq %0 = %1\n" \
-			      ";;\n" \
-			      "tbit.nz p6,p0 = %0, 31\n" \
-			      "(p6) br.cond.sptk.few 3b\n" \
-			      "br.cond.sptk.few 1b\n" \
-			      ";;\n" \
-			      ".previous\n": "=r" (tmp), "=m" (__atomic_fool_gcc(rw))); \
+#define read_lock(rw)									\
+do {											\
+	int tmp = 0;									\
+	__asm__ __volatile__ ("1:\tfetchadd4.acq %0 = %1, 1\n"				\
+			      ";;\n"							\
+			      "tbit.nz p6,p0 = %0, 31\n"				\
+			      "(p6) br.cond.sptk.few 2f\n"				\
+			      ".section .text.lock,\"ax\"\n"				\
+			      "2:\tfetchadd4.rel %0 = %1, -1\n"				\
+			      ";;\n"							\
+			      "3:\tld4.acq %0 = %1\n"					\
+			      ";;\n"							\
+			      "tbit.nz p6,p0 = %0, 31\n"				\
+			      "(p6) br.cond.sptk.few 3b\n"				\
+			      "br.cond.sptk.few 1b\n"					\
+			      ";;\n"							\
+			      ".previous\n": "=r" (tmp), "=m" (__atomic_fool_gcc(rw)));	\
 } while(0)
 
-#define read_unlock(rw) \
-do { \
-	int tmp = 0; \
-	__asm__ __volatile__ ("fetchadd4.rel %0 = %1, -1\n" \
-			      : "=r" (tmp) : "m" (__atomic_fool_gcc(rw))); \
+#define read_unlock(rw)								\
+do {										\
+	int tmp = 0;								\
+	__asm__ __volatile__ ("fetchadd4.rel %0 = %1, -1\n"			\
+			      : "=r" (tmp) : "m" (__atomic_fool_gcc(rw)));	\
 } while(0)
 
-/*
- * These may need to be rewhacked in asm().
- * XXX FIXME SDV - This may have a race on real hardware but is sufficient for SoftSDV
- */
-#define write_lock(rw) \
-while(1) {\
-	do { \
-	} while (!test_and_set_bit(31, (rw))); \
-	if ((rw)->read_counter) { \
-		clear_bit(31, (rw)); \
-		while ((rw)->read_counter) \
-			; \
-	} else { \
-		break; \
-	} \
+#define write_lock(rw)				\
+while(1) {					\
+	do {					\
+	} while (!test_and_set_bit(31, (rw)));	\
+	if ((rw)->read_counter) {		\
+		clear_bit(31, (rw));		\
+		while ((rw)->read_counter)	\
+			;			\
+	} else {				\
+		break;				\
+	}					\
 }
 
 #define write_unlock(x)				(clear_bit(31, (x)))
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h
--- v2.3.99-pre5/linux/include/asm-ia64/system.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/system.h	Fri Apr 21 15:21:24 2000
@@ -323,7 +323,7 @@
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) (*(struct __xchg_dummy *)(x))
 
-#define ia64_cmpxchg(ptr,old,new,size)					\
+#define ia64_cmpxchg(sem,ptr,old,new,size)				\
 ({									\
 	__typeof__(ptr) _p_ = (ptr);					\
 	__typeof__(new) _n_ = (new);					\
@@ -336,28 +336,28 @@
 	      case 8: _o_ = (__u64) (old); break;			\
 	      default:							\
 	}								\
-	 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "r"(_o_));		\
+	 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_));		\
 	switch (size) {							\
 	      case 1:							\
-		__asm__ __volatile__ ("cmpxchg1.rel %0=%2,%3,ar.ccv"	\
+		__asm__ __volatile__ ("cmpxchg1."sem" %0=%2,%3,ar.ccv"	\
 				      : "=r"(_r_), "=m"(__xg(_p_))	\
 				      : "m"(__xg(_p_)), "r"(_n_));	\
 		break;							\
 									\
 	      case 2:							\
-		__asm__ __volatile__ ("cmpxchg2.rel %0=%2,%3,ar.ccv"	\
+		__asm__ __volatile__ ("cmpxchg2."sem" %0=%2,%3,ar.ccv"	\
 				      : "=r"(_r_), "=m"(__xg(_p_))	\
 				      : "m"(__xg(_p_)), "r"(_n_));	\
 		break;							\
 									\
 	      case 4:							\
-		__asm__ __volatile__ ("cmpxchg4.rel %0=%2,%3,ar.ccv"	\
+		__asm__ __volatile__ ("cmpxchg4."sem" %0=%2,%3,ar.ccv"	\
 				      : "=r"(_r_), "=m"(__xg(_p_))	\
 				      : "m"(__xg(_p_)), "r"(_n_));	\
 		break;							\
 									\
 	      case 8:							\
-		__asm__ __volatile__ ("cmpxchg8.rel %0=%2,%3,ar.ccv"	\
+		__asm__ __volatile__ ("cmpxchg8."sem" %0=%2,%3,ar.ccv"	\
 				      : "=r"(_r_), "=m"(__xg(_p_))	\
 				      : "m"(__xg(_p_)), "r"(_n_));	\
 		break;							\
@@ -369,7 +369,11 @@
 	(__typeof__(old)) _r_;						\
 })
 
-#define cmpxchg(ptr,o,n)     ia64_cmpxchg((ptr), (o), (n), sizeof(*(ptr)))
+#define cmpxchg_acq(ptr,o,n)	ia64_cmpxchg("acq", (ptr), (o), (n), sizeof(*(ptr)))
+#define cmpxchg_rel(ptr,o,n)	ia64_cmpxchg("rel", (ptr), (o), (n), sizeof(*(ptr)))
+
+/* for compatibility with other platforms: */
+#define cmpxchg(ptr,o,n)	cmpxchg_acq(ptr,o,n)
 
 #ifdef CONFIG_IA64_DEBUG_CMPXCHG
 # define CMPXCHG_BUGCHECK_DECL	int _cmpxchg_bugcheck_count = 128;
@@ -396,24 +400,24 @@
 #define prepare_to_switch()    do { } while(0)
 
 #ifdef CONFIG_IA32_SUPPORT
-# define TASK_TO_PTREGS(t)									\
-	((struct pt_regs *)(((unsigned long)(t) + IA64_STK_OFFSET - IA64_PT_REGS_SIZE)))
 # define IS_IA32_PROCESS(regs)	(ia64_psr(regs)->is != 0)
-# define IA32_FP_STATE(prev,next)						\
-	if (IS_IA32_PROCESS(TASK_TO_PTREGS(prev))) {				\
+# define IA32_STATE(prev,next)							\
+	if (IS_IA32_PROCESS(ia64_task_regs(prev))) {				\
+	    __asm__ __volatile__("mov %0=ar.eflag":"=r"((prev)->thread.eflag));	\
 	    __asm__ __volatile__("mov %0=ar.fsr":"=r"((prev)->thread.fsr));	\
 	    __asm__ __volatile__("mov %0=ar.fcr":"=r"((prev)->thread.fcr));	\
 	    __asm__ __volatile__("mov %0=ar.fir":"=r"((prev)->thread.fir));	\
 	    __asm__ __volatile__("mov %0=ar.fdr":"=r"((prev)->thread.fdr));	\
 	}									\
-	if (IS_IA32_PROCESS(TASK_TO_PTREGS(next))) {				\
+	if (IS_IA32_PROCESS(ia64_task_regs(next))) {				\
+	    __asm__ __volatile__("mov ar.eflag=%0"::"r"((next)->thread.eflag));	\
 	    __asm__ __volatile__("mov ar.fsr=%0"::"r"((next)->thread.fsr));	\
 	    __asm__ __volatile__("mov ar.fcr=%0"::"r"((next)->thread.fcr));	\
 	    __asm__ __volatile__("mov ar.fir=%0"::"r"((next)->thread.fir));	\
 	    __asm__ __volatile__("mov ar.fdr=%0"::"r"((next)->thread.fdr));	\
 	}
 #else /* !CONFIG_IA32_SUPPORT */
-# define IA32_FP_STATE(prev,next)
+# define IA32_STATE(prev,next)
 # define IS_IA32_PROCESS(regs)		0
 #endif /* CONFIG_IA32_SUPPORT */
 
@@ -436,7 +440,7 @@
 	if ((next)->thread.flags & IA64_THREAD_DBG_VALID) {			\
 		ia64_load_debug_regs(&(next)->thread.dbr[0]);			\
 	}									\
-	IA32_FP_STATE(prev,next);						\
+	IA32_STATE(prev,next);							\
 	(last) = ia64_switch_to((next));					\
 } while (0)
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/types.h linux/include/asm-ia64/types.h
--- v2.3.99-pre5/linux/include/asm-ia64/types.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-ia64/types.h	Fri Apr 21 15:21:24 2000
@@ -13,10 +13,10 @@
  */
 
 #ifdef __ASSEMBLY__
-# define __IA64_UL(x)		x
+# define __IA64_UL(x)		(x)
 # define __IA64_UL_CONST(x)	x
 #else
-# define __IA64_UL(x)		((unsigned long)x)
+# define __IA64_UL(x)		((unsigned long)(x))
 # define __IA64_UL_CONST(x)	x##UL
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/uaccess.h linux/include/asm-ia64/uaccess.h
--- v2.3.99-pre5/linux/include/asm-ia64/uaccess.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/uaccess.h	Fri Apr 21 15:21:24 2000
@@ -71,10 +71,6 @@
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
  *
- * As the alpha uses the same address space for kernel and user
- * data, we can just do these as direct assignments.  (Of course, the
- * exception handling means that it's no longer "just"...)
- *
  * Careful to not
  * (a) re-use the arguments for side effects (sizeof/typeof is ok)
  * (b) require any knowledge of processes at this stage
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ia64/unistd.h linux/include/asm-ia64/unistd.h
--- v2.3.99-pre5/linux/include/asm-ia64/unistd.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/unistd.h	Fri Apr 21 15:21:24 2000
@@ -197,6 +197,8 @@
 #define __NR_sendmsg			1205
 #define __NR_recvmsg			1206
 #define __NR_sys_pivot_root		1207
+#define __NR_mincore			1208
+#define __NR_madvise			1209
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h
--- v2.3.99-pre5/linux/include/asm-m68k/elf.h	Thu Nov 18 20:25:38 1999
+++ linux/include/asm-m68k/elf.h	Thu Apr 13 08:11:49 2000
@@ -89,8 +89,7 @@
 #define ELF_PLATFORM  (NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) \
-	current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 #endif
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-mips/elf.h linux/include/asm-mips/elf.h
--- v2.3.99-pre5/linux/include/asm-mips/elf.h	Sat Feb 26 22:31:56 2000
+++ linux/include/asm-mips/elf.h	Thu Apr 13 08:11:49 2000
@@ -75,8 +75,7 @@
 #define ELF_ET_DYN_BASE         (2 * TASK_SIZE / 3)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex,ibcs2) \
-	current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 #endif
 
 #endif /* __ASM_MIPS_ELF_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-mips64/elf.h linux/include/asm-mips64/elf.h
--- v2.3.99-pre5/linux/include/asm-mips64/elf.h	Sat Feb 26 22:31:57 2000
+++ linux/include/asm-mips64/elf.h	Thu Apr 13 08:11:49 2000
@@ -91,9 +91,9 @@
 	else						\
 		current->thread.mflags &= ~MF_32BIT;	\
 	if (ibcs2)					\
-		current->personality = PER_SVR4;	\
+		set_personality(PER_SVR4);		\
 	else if (current->personality != PER_LINUX32)	\
-		current->personality = PER_LINUX;	\
+		set_personality(PER_LINUX);		\
 } while (0)
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h
--- v2.3.99-pre5/linux/include/asm-ppc/atomic.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-ppc/atomic.h	Mon Apr 24 13:39:36 2000
@@ -5,7 +5,9 @@
 #ifndef _ASM_PPC_ATOMIC_H_ 
 #define _ASM_PPC_ATOMIC_H_
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 typedef struct { volatile int counter; } atomic_t;
 #else
 typedef struct { int counter; } atomic_t;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/elf.h linux/include/asm-ppc/elf.h
--- v2.3.99-pre5/linux/include/asm-ppc/elf.h	Mon Mar 27 08:08:31 2000
+++ linux/include/asm-ppc/elf.h	Thu Apr 13 08:11:49 2000
@@ -66,8 +66,7 @@
 #define ELF_PLATFORM	(NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) \
-	current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 #endif
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h
--- v2.3.99-pre5/linux/include/asm-ppc/hardirq.h	Wed Feb 16 17:03:52 2000
+++ linux/include/asm-ppc/hardirq.h	Mon Apr 24 13:39:36 2000
@@ -15,7 +15,7 @@
 
 #define in_irq() (local_irq_count[smp_processor_id()] != 0)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
@@ -25,7 +25,7 @@
 
 #define synchronize_irq()	do { } while (0)
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 
 #include <asm/atomic.h>
 
@@ -80,6 +80,6 @@
 
 extern void synchronize_irq(void);
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #endif /* __ASM_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/pgalloc.h linux/include/asm-ppc/pgalloc.h
--- v2.3.99-pre5/linux/include/asm-ppc/pgalloc.h	Tue Dec  7 09:32:51 1999
+++ linux/include/asm-ppc/pgalloc.h	Mon Apr 24 13:39:36 2000
@@ -1,6 +1,7 @@
 #ifndef _PPC_PGALLOC_H
 #define _PPC_PGALLOC_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 #include <asm/processor.h>
 
@@ -18,7 +19,7 @@
  * I need to generalize this so we can use it for other arch's as well.
  * -- Cort
  */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define quicklists	cpu_data[smp_processor_id()]
 #else
 extern struct pgtable_cache_struct {
@@ -54,7 +55,7 @@
 {
 	struct task_struct * p;
 	pgd_t *pgd;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int i;
 #endif	
         
@@ -65,7 +66,7 @@
 		*pgd_offset(p->mm,address) = entry;
 	}
 	read_unlock(&tasklist_lock);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
 		pgd[address >> PGDIR_SHIFT] = entry;
 #else
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.3.99-pre5/linux/include/asm-ppc/pgtable.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-ppc/pgtable.h	Mon Apr 24 13:39:36 2000
@@ -230,7 +230,7 @@
 
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define _PAGE_BASE	_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT
 #else
 #define _PAGE_BASE	_PAGE_PRESENT | _PAGE_ACCESSED
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.3.99-pre5/linux/include/asm-ppc/smp.h	Sun Feb 13 19:29:04 2000
+++ linux/include/asm-ppc/smp.h	Mon Apr 24 13:39:36 2000
@@ -6,9 +6,10 @@
 #ifndef _PPC_SMP_H
 #define _PPC_SMP_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #ifndef __ASSEMBLY__
 
@@ -50,8 +51,8 @@
 
 #endif /* __ASSEMBLY__ */
 
-#else /* !(__SMP__) */
+#else /* !(CONFIG_SMP) */
 
-#endif /* !(__SMP__) */
+#endif /* !(CONFIG_SMP) */
 
 #endif /* !(_PPC_SMP_H) */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.3.99-pre5/linux/include/asm-ppc/system.h	Sat Feb 26 22:31:59 2000
+++ linux/include/asm-ppc/system.h	Mon Apr 24 13:39:36 2000
@@ -6,6 +6,7 @@
 #ifndef __PPC_SYSTEM_H
 #define __PPC_SYSTEM_H
 
+#include <linux/config.h>
 #include <linux/kdev_t.h>
 
 #include <asm/processor.h>
@@ -86,7 +87,7 @@
 struct pt_regs;
 extern void dump_regs(struct pt_regs *);
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define cli()	__cli()
 #define sti()	__sti()
@@ -94,7 +95,7 @@
 #define restore_flags(flags)	__restore_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 
 extern void __global_cli(void);
 extern void __global_sti(void);
@@ -105,7 +106,7 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 
-#endif /* !__SMP__ */
+#endif /* !CONFIG_SMP */
 
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-ppc/timex.h linux/include/asm-ppc/timex.h
--- v2.3.99-pre5/linux/include/asm-ppc/timex.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-ppc/timex.h	Mon Apr 24 13:39:36 2000
@@ -6,6 +6,8 @@
 #ifndef _ASMppc_TIMEX_H
 #define _ASMppc_TIMEX_H
 
+#include <linux/config.h>
+
 #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
@@ -26,7 +28,7 @@
 
 static inline cycles_t get_cycles(void)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	cycles_t ret;
 
 	__asm__("mftb %0" : "=r" (ret) : );
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/atomic.h linux/include/asm-sh/atomic.h
--- v2.3.99-pre5/linux/include/asm-sh/atomic.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/atomic.h	Tue Apr 25 16:53:13 2000
@@ -7,7 +7,9 @@
  *
  */
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 typedef struct { volatile int counter; } atomic_t;
 #else
 typedef struct { int counter; } atomic_t;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/current.h linux/include/asm-sh/current.h
--- v2.3.99-pre5/linux/include/asm-sh/current.h	Tue Apr 11 15:09:23 2000
+++ linux/include/asm-sh/current.h	Mon Apr 24 13:54:17 2000
@@ -12,10 +12,9 @@
 {
 	struct task_struct *current;
 
-	__asm__("stc	$r4_bank, %0\n\t"
-		"add	%1, %0"
-		:"=&r" (current)
-		:"r" (-8192));
+	__asm__("stc	$r7_bank, %0"
+		:"=r" (current));
+
 	return current;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/delay.h linux/include/asm-sh/delay.h
--- v2.3.99-pre5/linux/include/asm-sh/delay.h	Tue Apr 11 15:09:23 2000
+++ linux/include/asm-sh/delay.h	Tue Apr 25 16:53:13 2000
@@ -5,6 +5,8 @@
  * Copyright (C) 1999  Kaz Kojima
  */
 
+#include <linux/config.h>
+
 extern __inline__ void __delay(unsigned long loops)
 {
 	__asm__ __volatile__(
@@ -28,7 +30,7 @@
 }
 
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define __udelay_val cpu_data[smp_processor_id()].udelay_val
 #else
 #define __udelay_val loops_per_sec
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/elf.h linux/include/asm-sh/elf.h
--- v2.3.99-pre5/linux/include/asm-sh/elf.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sh/elf.h	Mon Apr 24 13:54:17 2000
@@ -66,11 +66,11 @@
   do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \
        _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \
        _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \
-       _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; } while (0)
+       _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; \
+       _r->sr = SR_FD; } while (0)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) \
-	current->personality = PER_LINUX_32BIT
+#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
 #endif
 
 #endif /* __ASM_SH_ELF_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/hardirq.h linux/include/asm-sh/hardirq.h
--- v2.3.99-pre5/linux/include/asm-sh/hardirq.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sh/hardirq.h	Tue Apr 25 16:53:13 2000
@@ -1,14 +1,22 @@
 #ifndef __ASM_SH_HARDIRQ_H
 #define __ASM_SH_HARDIRQ_H
 
+#include <linux/config.h>
 #include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
+extern unsigned int local_bh_count[NR_CPUS];
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+	(local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
 
 #define in_irq() (local_irq_count[smp_processor_id()] != 0)
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
@@ -22,5 +30,5 @@
 
 #error Super-H SMP is not available
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 #endif /* __ASM_SH_HARDIRQ_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/ptrace.h linux/include/asm-sh/ptrace.h
--- v2.3.99-pre5/linux/include/asm-sh/ptrace.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sh/ptrace.h	Mon Apr 24 13:54:17 2000
@@ -7,19 +7,23 @@
  */
 
 /*
- * As GCC does:
- *  0 - 15 are integer registers
- * 17 - 22 are control/special registers
- * 24 - 39 fp registers
- * 40 - 47 xd registers
- * 48 -    fpscr register
+ * GCC defines register number like this:
  * -----------------------------
- * Not as GCC:
- * 16 --- program counter PC
- * 23 --- syscall #
+ *	 0 - 15 are integer registers
+ *	17 - 22 are control/special registers
+ *	24 - 39 fp registers
+ *	40 - 47 xd registers
+ *	48 -    fpscr register
+ * -----------------------------
+ *
+ * We follows above, except:
+ *	16 --- program counter (PC)
+ *	22 --- syscall #
+ *	23 --- floating point communication register
  */
 #define REG_REG0	 0
 #define REG_REG15	15
+
 #define REG_PC		16
 
 #define REG_PR		17
@@ -27,9 +31,10 @@
 #define REG_GBR      	19
 #define REG_MACH	20
 #define REG_MACL	21
-#define REG_FPUL	22
 
-#define REG_SYSCALL	23
+#define REG_SYSCALL	22
+
+#define REG_FPUL	23
 
 #define REG_FPREG0	24
 #define REG_FPREG15	39
@@ -42,14 +47,14 @@
  * kernel stack during a system call or other kernel entry.
  */
 struct pt_regs {
-	long syscall_nr;
-	unsigned long sr;
 	unsigned long regs[16];
+	unsigned long pc;
+	unsigned long pr;
+	unsigned long sr;
 	unsigned long gbr;
 	unsigned long mach;
 	unsigned long macl;
-	unsigned long pr;
-	unsigned long pc;
+	long syscall_nr;
 };
 
 #ifdef __KERNEL__
@@ -60,18 +65,17 @@
 /* User Break Controller */
 
 #if defined(__sh3__)
-/* The value is for sh4, please fix... */
-#define UBC_BARA		0xff200000
-#define UBC_BAMRA		0xff200004
-#define UBC_BBRA		0xff200008
-#define UBC_BASRA		0xff000014
-#define UBC_BARB		0xff20000c
-#define UBC_BAMRB		0xff200010
-#define UBC_BBRB		0xff200014
-#define UBC_BASRB		0xff000018
-#define UBC_BDRB		0xff200018
-#define UBC_BDMRB		0xff20001c
-#define UBC_BRCR		0xff200020
+#define UBC_BARA                0xffffffb0
+#define UBC_BAMRA               0xffffffb4
+#define UBC_BBRA                0xffffffb8
+#define UBC_BASRA               0xffffffe4
+#define UBC_BARB                0xffffffa0
+#define UBC_BAMRB               0xffffffa4
+#define UBC_BBRB                0xffffffa8
+#define UBC_BASRB               0xffffffe8
+#define UBC_BDRB                0xffffff90
+#define UBC_BDMRB               0xffffff94
+#define UBC_BRCR                0xffffff98
 #elif defined(__SH4__)
 #define UBC_BARA		0xff200000
 #define UBC_BAMRA		0xff200004
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/sigcontext.h linux/include/asm-sh/sigcontext.h
--- v2.3.99-pre5/linux/include/asm-sh/sigcontext.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sh/sigcontext.h	Mon Apr 24 13:54:17 2000
@@ -6,12 +6,12 @@
 
 	/* CPU registers */
 	unsigned long sc_regs[16];
+	unsigned long sc_pc;
+	unsigned long sc_pr;
+	unsigned long sc_sr;
 	unsigned long sc_gbr;
 	unsigned long sc_mach;
 	unsigned long sc_macl;
-	unsigned long sc_pr;
-	unsigned long sc_sr;
-	unsigned long sc_pc;
 
 #if defined(__SH4__)
 	/* FPU registers */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/smplock.h linux/include/asm-sh/smplock.h
--- v2.3.99-pre5/linux/include/asm-sh/smplock.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/smplock.h	Tue Apr 25 16:53:13 2000
@@ -7,7 +7,9 @@
  * for more details.
  */
 
-#ifndef __SMP__
+#include <linux/config.h>
+
+#ifndef CONFIG_SMP
 
 #define lock_kernel()				do { } while(0)
 #define unlock_kernel()				do { } while(0)
@@ -65,6 +67,6 @@
 		spin_lock(&kernel_flag); \
 } while (0)
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #endif /* __ASM_SH_SMPLOCK_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/softirq.h linux/include/asm-sh/softirq.h
--- v2.3.99-pre5/linux/include/asm-sh/softirq.h	Tue Mar  7 14:32:26 2000
+++ linux/include/asm-sh/softirq.h	Mon Apr 24 13:54:17 2000
@@ -4,8 +4,6 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-extern unsigned int local_bh_count[NR_CPUS];
-
 #define cpu_bh_disable(cpu)	do { local_bh_count[(cpu)]++; barrier(); } while (0)
 #define cpu_bh_enable(cpu)	do { barrier(); local_bh_count[(cpu)]--; } while (0)
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/system.h linux/include/asm-sh/system.h
--- v2.3.99-pre5/linux/include/asm-sh/system.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sh/system.h	Tue Apr 25 16:53:13 2000
@@ -5,6 +5,8 @@
  * Copyright (C) 1999, 2000  Niibe Yutaka  &  Kaz Kojima
  */
 
+#include <linux/config.h>
+
 /*
  *	switch_to() should switch tasks to task nr n, first
  */
@@ -13,7 +15,7 @@
 	unsigned long seg;
 } mm_segment_t;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #error no SMP SuperH
 #else
 #define prepare_to_switch()	do { } while(0)
@@ -97,11 +99,11 @@
 
 	__asm__ __volatile__("stc	$sr, %0\n\t"
 			     "and	%1, %0\n\t"
-			     "stc	$r5_bank, %1\n\t"
+			     "stc	$r6_bank, %1\n\t"
 			     "or	%1, %0\n\t"
 			     "ldc	%0, $sr"
 			     : "=&r" (__dummy0), "=r" (__dummy1)
-			     : "1" (~0xf0)
+			     : "1" (~0x000000f0)
 			     : "memory");
 }
 
@@ -137,17 +139,8 @@
 		: "memory"); (__sr & 0x000000f0); }))
 
 #define __restore_flags(x) do { 			\
-	unsigned long __dummy0, __dummy1;		\
-	if (x != 0xf0)	/* not CLI-ed? */		\
-		__asm__ __volatile__(		       	\
-		"stc	$sr, %0\n\t"			\
-		"and	%1, %0\n\t"			\
-		"stc	$r5_bank, %1\n\t"		\
-		"or	%1, %0\n\t"			\
-		"ldc	%0, $sr"			\
-		: "=&r" (__dummy0), "=r" (__dummy1)	\
-		: "1" (0xffffff0f)	 		\
-		: "memory"); 				\
+	if (x != 0x000000f0)	/* not CLI-ed? */		\
+		__sti();				\
 } while (0)
 
 /*
@@ -192,7 +185,7 @@
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 extern void __global_cli(void);
 extern void __global_sti(void);
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sh/unistd.h linux/include/asm-sh/unistd.h
--- v2.3.99-pre5/linux/include/asm-sh/unistd.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sh/unistd.h	Mon Apr 24 13:54:17 2000
@@ -248,8 +248,8 @@
 #define _syscall0(type,name) \
 type name(void) \
 { \
-register long __sc0 __asm__ ("$r0") = __NR_##name; \
-__asm__ __volatile__ ("trapa	#0" \
+register long __sc0 __asm__ ("$r3") = __NR_##name; \
+__asm__ __volatile__ ("trapa	#0x10" \
 	: "=z" (__sc0) \
 	: "0" (__sc0) \
 	: "memory" ); \
@@ -259,9 +259,9 @@
 #define _syscall1(type,name,type1,arg1) \
 type name(type1 arg1) \
 { \
-register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc0 __asm__ ("$r3") = __NR_##name; \
 register long __sc4 __asm__ ("$r4") = (long) arg1; \
-__asm__ __volatile__ ("trapa	#0" \
+__asm__ __volatile__ ("trapa	#0x11" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4) \
 	: "memory"); \
@@ -271,10 +271,10 @@
 #define _syscall2(type,name,type1,arg1,type2,arg2) \
 type name(type1 arg1,type2 arg2) \
 { \
-register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc0 __asm__ ("$r3") = __NR_##name; \
 register long __sc4 __asm__ ("$r4") = (long) arg1; \
 register long __sc5 __asm__ ("$r5") = (long) arg2; \
-__asm__ __volatile__ ("trapa	#0" \
+__asm__ __volatile__ ("trapa	#0x12" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4), "r" (__sc5) \
 	: "memory"); \
@@ -284,11 +284,11 @@
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
 type name(type1 arg1,type2 arg2,type3 arg3) \
 { \
-register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc0 __asm__ ("$r3") = __NR_##name; \
 register long __sc4 __asm__ ("$r4") = (long) arg1; \
 register long __sc5 __asm__ ("$r5") = (long) arg2; \
 register long __sc6 __asm__ ("$r6") = (long) arg3; \
-__asm__ __volatile__ ("trapa	#0" \
+__asm__ __volatile__ ("trapa	#0x13" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) \
 	: "memory"); \
@@ -298,12 +298,12 @@
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
 { \
-register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc0 __asm__ ("$r3") = __NR_##name; \
 register long __sc4 __asm__ ("$r4") = (long) arg1; \
 register long __sc5 __asm__ ("$r5") = (long) arg2; \
 register long __sc6 __asm__ ("$r6") = (long) arg3; \
 register long __sc7 __asm__ ("$r7") = (long) arg4; \
-__asm__ __volatile__ ("trapa	#0" \
+__asm__ __volatile__ ("trapa	#0x14" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6),  \
 	  "r" (__sc7) \
@@ -314,16 +314,16 @@
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
 { \
-register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc0 __asm__ ("$r3") = __NR_##name; \
 register long __sc4 __asm__ ("$r4") = (long) arg1; \
 register long __sc5 __asm__ ("$r5") = (long) arg2; \
 register long __sc6 __asm__ ("$r6") = (long) arg3; \
 register long __sc7 __asm__ ("$r7") = (long) arg4; \
-__asm__ __volatile__ ("mov.l	%2, @-$r15\n\t" \
-		      "trapa	#0" \
+register long __sc2 __asm__ ("$r0") = (long) arg5; \
+__asm__ __volatile__ ("trapa	#0x15" \
 	: "=z" (__sc0) \
-	: "0" (__sc0), "r" (arg5), \
-	  "r" (__sc4), "r" (__sc5), "r" (__sc6), "r" (__sc7) \
+	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), "r" (__sc7),  \
+	  "r" (__sc7), "r" (__sc2) \
 	: "memory" ); \
 __syscall_return(type,__sc0); \
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h
--- v2.3.99-pre5/linux/include/asm-sparc/asm_offsets.h	Mon Mar 27 08:08:31 2000
+++ linux/include/asm-sparc/asm_offsets.h	Tue Apr 25 17:52:01 2000
@@ -228,21 +228,25 @@
 #define ASIZ_mm_env_start	0x00000004
 #define AOFF_mm_env_end	0x0000006c
 #define ASIZ_mm_env_end	0x00000004
-#define AOFF_mm_rss	0x00000070
+#define AOFF_mm_min_flt	0x00000070
+#define ASIZ_mm_min_flt	0x00000004
+#define AOFF_mm_maj_flt	0x00000074
+#define ASIZ_mm_maj_flt	0x00000004
+#define AOFF_mm_rss	0x00000078
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x00000074
+#define AOFF_mm_total_vm	0x0000007c
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000078
+#define AOFF_mm_locked_vm	0x00000080
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x0000007c
+#define AOFF_mm_def_flags	0x00000084
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_cpu_vm_mask	0x00000080
+#define AOFF_mm_cpu_vm_mask	0x00000088
 #define ASIZ_mm_cpu_vm_mask	0x00000004
-#define AOFF_mm_swap_cnt	0x00000084
+#define AOFF_mm_swap_cnt	0x0000008c
 #define ASIZ_mm_swap_cnt	0x00000004
-#define AOFF_mm_swap_address	0x00000088
+#define AOFF_mm_swap_address	0x00000090
 #define ASIZ_mm_swap_address	0x00000004
-#define AOFF_mm_segments	0x0000008c
+#define AOFF_mm_segments	0x00000094
 #define ASIZ_mm_segments	0x00000004
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
@@ -509,21 +513,25 @@
 #define ASIZ_mm_env_start	0x00000004
 #define AOFF_mm_env_end	0x00000074
 #define ASIZ_mm_env_end	0x00000004
-#define AOFF_mm_rss	0x00000078
+#define AOFF_mm_min_flt	0x00000078
+#define ASIZ_mm_min_flt	0x00000004
+#define AOFF_mm_maj_flt	0x0000007c
+#define ASIZ_mm_maj_flt	0x00000004
+#define AOFF_mm_rss	0x00000080
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x0000007c
+#define AOFF_mm_total_vm	0x00000084
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000080
+#define AOFF_mm_locked_vm	0x00000088
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x00000084
+#define AOFF_mm_def_flags	0x0000008c
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_cpu_vm_mask	0x00000088
+#define AOFF_mm_cpu_vm_mask	0x00000090
 #define ASIZ_mm_cpu_vm_mask	0x00000004
-#define AOFF_mm_swap_cnt	0x0000008c
+#define AOFF_mm_swap_cnt	0x00000094
 #define ASIZ_mm_swap_cnt	0x00000004
-#define AOFF_mm_swap_address	0x00000090
+#define AOFF_mm_swap_address	0x00000098
 #define ASIZ_mm_swap_address	0x00000004
-#define AOFF_mm_segments	0x00000094
+#define AOFF_mm_segments	0x0000009c
 #define ASIZ_mm_segments	0x00000004
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc/elf.h linux/include/asm-sparc/elf.h
--- v2.3.99-pre5/linux/include/asm-sparc/elf.h	Sun Oct  4 10:22:44 1998
+++ linux/include/asm-sparc/elf.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.20 1998/09/14 09:11:10 davem Exp $ */
+/* $Id: elf.h,v 1.21 2000/04/14 09:59:04 davem Exp $ */
 #ifndef __ASMSPARC_ELF_H
 #define __ASMSPARC_ELF_H
 
@@ -105,8 +105,7 @@
 #define ELF_PLATFORM	(NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) \
-	current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
 #endif
 
 #endif /* !(__ASMSPARC_ELF_H) */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- v2.3.99-pre5/linux/include/asm-sparc/io.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc/io.h	Fri Apr 14 09:37:10 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: io.h,v 1.26 2000/03/30 01:43:26 davem Exp $
+ * $Id: io.h,v 1.27 2000/04/13 04:45:59 davem Exp $
  */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
@@ -169,6 +169,7 @@
  * This is why we have no bus number argument to ioremap().
  */
 extern void *ioremap(unsigned long offset, unsigned long size);
+#define ioremap_nocache(X,Y)	ioremap((X),(Y))
 extern void iounmap(void *addr);
 
 /* P3: talk davem into dropping "name" argument in favor of res->name */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc/jsflash.h linux/include/asm-sparc/jsflash.h
--- v2.3.99-pre5/linux/include/asm-sparc/jsflash.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc/jsflash.h	Wed Apr 26 12:13:16 2000
@@ -36,4 +36,4 @@
 	__u32 size;
 };
 
-#endif /* _SPARC_IDE_H */
+#endif /* _SPARC_JSFLASH_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc/namei.h linux/include/asm-sparc/namei.h
--- v2.3.99-pre5/linux/include/asm-sparc/namei.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc/namei.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.14 1999/06/10 05:23:12 davem Exp $
+/* $Id: namei.h,v 1.16 2000/04/13 00:55:54 davem Exp $
  * linux/include/asm-sparc/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -14,7 +14,7 @@
 static inline char * __emul_prefix(void)
 {
 	switch (current->personality) {
-	case PER_BSD:
+	case PER_SUNOS:
 		return SPARC_BSD_EMUL;
 	case PER_SVR4:
 		return SPARC_SOL_EMUL;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.3.99-pre5/linux/include/asm-sparc64/asm_offsets.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc64/asm_offsets.h	Tue Apr 25 17:52:01 2000
@@ -235,23 +235,27 @@
 #define ASIZ_mm_env_start	0x00000008
 #define AOFF_mm_env_end	0x000000c8
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000d0
+#define AOFF_mm_min_flt	0x000000d0
+#define ASIZ_mm_min_flt	0x00000008
+#define AOFF_mm_maj_flt	0x000000d8
+#define ASIZ_mm_maj_flt	0x00000008
+#define AOFF_mm_rss	0x000000e0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000d8
+#define AOFF_mm_total_vm	0x000000e8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000e0
+#define AOFF_mm_locked_vm	0x000000f0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000e8
+#define AOFF_mm_def_flags	0x000000f8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000f0
+#define AOFF_mm_cpu_vm_mask	0x00000100
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000f8
+#define AOFF_mm_swap_cnt	0x00000108
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x00000100
+#define AOFF_mm_swap_address	0x00000110
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000108
+#define AOFF_mm_segments	0x00000118
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000110
+#define ASIZ_mm	0x00000120
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
@@ -529,23 +533,27 @@
 #define ASIZ_mm_env_start	0x00000008
 #define AOFF_mm_env_end	0x000000c8
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000d0
+#define AOFF_mm_min_flt	0x000000d0
+#define ASIZ_mm_min_flt	0x00000008
+#define AOFF_mm_maj_flt	0x000000d8
+#define ASIZ_mm_maj_flt	0x00000008
+#define AOFF_mm_rss	0x000000e0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000d8
+#define AOFF_mm_total_vm	0x000000e8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000e0
+#define AOFF_mm_locked_vm	0x000000f0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000e8
+#define AOFF_mm_def_flags	0x000000f8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000f0
+#define AOFF_mm_cpu_vm_mask	0x00000100
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000f8
+#define AOFF_mm_swap_cnt	0x00000108
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x00000100
+#define AOFF_mm_swap_address	0x00000110
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000108
+#define AOFF_mm_segments	0x00000118
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000110
+#define ASIZ_mm	0x00000120
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
@@ -821,23 +829,27 @@
 #define ASIZ_mm_env_start	0x00000008
 #define AOFF_mm_env_end	0x000000d8
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000e0
+#define AOFF_mm_min_flt	0x000000e0
+#define ASIZ_mm_min_flt	0x00000008
+#define AOFF_mm_maj_flt	0x000000e8
+#define ASIZ_mm_maj_flt	0x00000008
+#define AOFF_mm_rss	0x000000f0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000e8
+#define AOFF_mm_total_vm	0x000000f8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000f0
+#define AOFF_mm_locked_vm	0x00000100
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000f8
+#define AOFF_mm_def_flags	0x00000108
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x00000100
+#define AOFF_mm_cpu_vm_mask	0x00000110
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x00000108
+#define AOFF_mm_swap_cnt	0x00000118
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x00000110
+#define AOFF_mm_swap_address	0x00000120
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000118
+#define AOFF_mm_segments	0x00000128
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000120
+#define ASIZ_mm	0x00000130
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/delay.h linux/include/asm-sparc64/delay.h
--- v2.3.99-pre5/linux/include/asm-sparc64/delay.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc64/delay.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.7 1997/11/07 18:24:31 mj Exp $
+/* $Id: delay.h,v 1.8 2000/04/13 04:45:59 davem Exp $
  * delay.h: Linux delay routines on the V9.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu).
@@ -8,6 +8,7 @@
 #define __SPARC64_DELAY_H
 
 #ifdef __SMP__
+#include <linux/sched.h>
 #include <asm/smp.h>
 #endif 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h
--- v2.3.99-pre5/linux/include/asm-sparc64/elf.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc64/elf.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.23 1999/12/15 14:19:06 davem Exp $ */
+/* $Id: elf.h,v 1.24 2000/04/14 09:59:04 davem Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -96,9 +96,9 @@
 	}						\
 							\
 	if (ibcs2)					\
-		current->personality = PER_SVR4;	\
+		set_personality(PER_SVR4);		\
 	else if (current->personality != PER_LINUX32)	\
-		current->personality = PER_LINUX;	\
+		set_personality(PER_LINUX);		\
 } while (0)
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.3.99-pre5/linux/include/asm-sparc64/hardirq.h	Sat Feb 12 11:22:11 2000
+++ linux/include/asm-sparc64/hardirq.h	Tue Apr 25 17:52:01 2000
@@ -7,11 +7,17 @@
 #define __SPARC64_HARDIRQ_H
 
 #include <linux/threads.h>
+#include <linux/brlock.h>
+#include <linux/spinlock.h>
 
 #ifndef __SMP__
 extern unsigned int local_irq_count;
+#define irq_enter(cpu, irq)	(local_irq_count++)
+#define irq_exit(cpu, irq)	(local_irq_count--)
 #else
-#define local_irq_count		(cpu_data[smp_processor_id()].irq_count)
+#define local_irq_count		(__brlock_array[smp_processor_id()][BR_GLOBALIRQ_LOCK])
+#define irq_enter(cpu, irq)	br_read_lock(BR_GLOBALIRQ_LOCK)
+#define irq_exit(cpu, irq)	br_read_unlock(BR_GLOBALIRQ_LOCK)
 #endif
 
 /*
@@ -35,42 +41,33 @@
 
 #else /* (__SMP__) */
 
-#include <asm/atomic.h>
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <asm/smp.h>
+static __inline__ int irqs_running(void)
+{
+	enum brlock_indices idx = BR_GLOBALIRQ_LOCK;
+	int i, count = 0;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		count += (__brlock_array[cpu_logical_map(i)][idx] != 0);
+
+	return count;
+}
 
 extern unsigned char global_irq_holder;
-extern spinlock_t global_irq_lock;
-extern atomic_t global_irq_count;
 
 static inline void release_irqlock(int cpu)
 {
 	/* if we didn't own the irq lock, just ignore... */
 	if(global_irq_holder == (unsigned char) cpu) {
 		global_irq_holder = NO_PROC_ID;
-		spin_unlock(&global_irq_lock);
+		br_write_unlock(BR_GLOBALIRQ_LOCK);
 	}
 }
 
-static inline void hardirq_enter(int cpu)
-{
-	++(cpu_data[cpu].irq_count);
-	atomic_inc(&global_irq_count);
-	membar("#StoreLoad | #StoreStore");
-}
-
-static inline void hardirq_exit(int cpu)
-{
-	membar("#StoreStore | #LoadStore");
-	atomic_dec(&global_irq_count);
-	--(cpu_data[cpu].irq_count);
-}
-
 static inline int hardirq_trylock(int cpu)
 {
-	return (! atomic_read(&global_irq_count) &&
-		! spin_is_locked (&global_irq_lock));
+	spinlock_t *lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock;
+
+	return (!irqs_running() && !spin_is_locked(lock));
 }
 
 #define hardirq_endlock(cpu)	do { (void)(cpu); } while (0)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- v2.3.99-pre5/linux/include/asm-sparc64/io.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc64/io.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.34 2000/03/30 01:40:54 davem Exp $ */
+/* $Id: io.h,v 1.35 2000/04/13 04:45:59 davem Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
@@ -367,6 +367,7 @@
  * using physically addressed loads and stores, so this does nothing.
  */
 #define ioremap(__offset, __size)	((void *)(__offset))
+#define ioremap_nocache(X,Y)		ioremap((X),(Y))
 #define iounmap(__addr)			do { } while(0)
 
 /* Similarly for SBUS. */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.3.99-pre5/linux/include/asm-sparc64/namei.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc64/namei.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.15 1999/06/10 05:23:17 davem Exp $
+/* $Id: namei.h,v 1.17 2000/04/13 00:55:54 davem Exp $
  * linux/include/asm-sparc64/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -14,7 +14,7 @@
 static inline char * __emul_prefix(void)
 {
 	switch (current->personality) {
-	case PER_BSD:
+	case PER_SUNOS:
 		return SPARC_BSD_EMUL;
 	case PER_SVR4:
 		return SPARC_SOL_EMUL;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.3.99-pre5/linux/include/asm-sparc64/page.h	Mon Mar 27 08:08:31 2000
+++ linux/include/asm-sparc64/page.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.33 2000/03/22 02:48:04 davem Exp $ */
+/* $Id: page.h,v 1.35 2000/04/13 04:45:59 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -21,8 +21,10 @@
 #define BUG()		__builtin_trap()
 #define PAGE_BUG(page)	BUG()
 
-extern void clear_page(void *page);
-extern void copy_page(void *to, void *from);
+extern void _clear_page(void *page);
+extern void _copy_page(void *to, void *from);
+#define clear_page(X)	_clear_page((void *)(X))
+#define copy_page(X,Y)	_copy_page((void *)(X), (void *)(Y))
 extern void clear_user_page(void *page, unsigned long vaddr);
 extern void copy_user_page(void *to, void *from, unsigned long vaddr);
 
@@ -103,7 +105,7 @@
 
 #define __pa(x)			((unsigned long)(x) - PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
+#define MAP_NR(addr)		((__pa(addr)-phys_base) >> PAGE_SHIFT)
 
 #define virt_to_phys __pa
 #define phys_to_virt __va
@@ -119,8 +121,8 @@
  */
 
 struct sparc_phys_banks {
-  unsigned long base_addr;
-  unsigned long num_bytes;
+	unsigned long base_addr;
+	unsigned long num_bytes;
 };
 
 #define SPARC_PHYS_BANKS 32
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.3.99-pre5/linux/include/asm-sparc64/pgalloc.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc64/pgalloc.h	Fri Apr 14 09:37:10 2000
@@ -153,11 +153,11 @@
                 ret = (struct page *)(__page_address(ret) + off);
                 pgd_cache_size--;
         } else {
-		ret = (struct page *) __get_free_page(GFP_KERNEL);
-		if(ret) {
-			struct page *page = mem_map + MAP_NR(ret);
-			
-			memset(ret, 0, PAGE_SIZE);
+		struct page *page = alloc_page(GFP_KERNEL);
+
+		if (page) {
+			ret = (struct page *)page_address(page);
+			clear_page(ret);
 			(unsigned long)page->pprev_hash = 2;
 			(unsigned long *)page->next_hash = pgd_quicklist;
 			pgd_quicklist = (unsigned long *)page;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.99-pre5/linux/include/asm-sparc64/pgtable.h	Tue Apr 11 15:09:24 2000
+++ linux/include/asm-sparc64/pgtable.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.124 2000/03/27 10:38:56 davem Exp $
+/* $Id: pgtable.h,v 1.125 2000/04/12 08:10:26 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -152,16 +152,13 @@
 
 #define BAD_PAGE	__bad_page()
 
-/* First physical page can be anywhere, the following is needed so that
- * va-->pa and vice versa conversions work properly without performance
- * hit for all __pa()/__va() operations.
- */
 extern unsigned long phys_base;
-#define ZERO_PAGE(vaddr)	(mem_map + (phys_base>>PAGE_SHIFT))
+
+#define ZERO_PAGE(vaddr)	(mem_map)
 
 /* Warning: These take pointers to page structs now... */
 #define mk_pte(page, pgprot)		\
-	__pte(((page - mem_map) << PAGE_SHIFT) | pgprot_val(pgprot))
+	__pte((((page - mem_map) << PAGE_SHIFT)+phys_base) | pgprot_val(pgprot))
 #define page_pte_prot(page, prot)	mk_pte(page, prot)
 #define page_pte(page)			page_pte_prot(page, __pgprot(0))
 
@@ -180,7 +177,7 @@
 	(pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL))
 #define pgd_set(pgdp, pmdp)	\
 	(pgd_val(*(pgdp)) = (__pa((unsigned long) (pmdp)) >> 11UL))
-#define pte_pagenr(pte)   ((unsigned long) ((pte_val(pte)&~PAGE_OFFSET)>>PAGE_SHIFT))
+#define pte_pagenr(pte)   (((unsigned long) ((pte_val(pte)&~PAGE_OFFSET)-phys_base)>>PAGE_SHIFT))
 #define pmd_page(pmd)			((unsigned long) __va((pmd_val(pmd)<<11UL)))
 #define pgd_page(pgd)			((unsigned long) __va((pgd_val(pgd)<<11UL)))
 #define pte_none(pte) 			(!pte_val(pte))
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/sab82532.h linux/include/asm-sparc64/sab82532.h
--- v2.3.99-pre5/linux/include/asm-sparc64/sab82532.h	Wed May 12 08:41:15 1999
+++ linux/include/asm-sparc64/sab82532.h	Fri Apr 14 09:37:10 2000
@@ -1,4 +1,4 @@
-/* $Id: sab82532.h,v 1.5 1999/05/12 11:21:22 davem Exp $
+/* $Id: sab82532.h,v 1.6 2000/04/13 07:22:35 ecd Exp $
  * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -144,6 +144,8 @@
 	int				 recv_fifo_size;
 	int				 custom_divisor;
 	int				 baud;
+	unsigned int			 cec_timeout;
+	unsigned int			 tec_timeout;
 	int				 x_char;
 	int				 close_delay;
 	unsigned short			 closing_wait;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.3.99-pre5/linux/include/asm-sparc64/smp.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/smp.h	Mon Apr 24 13:59:58 2000
@@ -33,12 +33,11 @@
 /* Keep this a multiple of 64-bytes for cache reasons. */
 struct cpuinfo_sparc {
 	/* Dcache line 1 */
-	unsigned int	irq_count;
 	unsigned int	bh_count;
 	unsigned int	multiplier;
 	unsigned int	counter;
 	unsigned int	idle_volume;
-	unsigned int	__pad;
+	unsigned int	__pad[2];
 	unsigned long	udelay_val;
 
 	/* Dcache line 2 */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h
--- v2.3.99-pre5/linux/include/asm-sparc64/ttable.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc64/ttable.h	Wed Apr 12 09:12:35 2000
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.14 1999/10/13 11:48:58 jj Exp $ */
+/* $Id: ttable.h,v 1.15 2000/04/03 10:36:42 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
@@ -85,7 +85,7 @@
 	sethi	%hi(109f), %g7;				\
 	ba,pt	%xcc, scetrap;				\
 109:	 or	%g7, %lo(109b), %g7;			\
-	call	routine;				\
+	ba,pt	%xcc, routine;				\
 	 sethi	%hi(systbl), %l7;			\
 	nop; nop; nop;
 	
diff -u --recursive --new-file v2.3.99-pre5/linux/include/asm-sparc64/vga.h linux/include/asm-sparc64/vga.h
--- v2.3.99-pre5/linux/include/asm-sparc64/vga.h	Thu Feb 25 10:02:12 1999
+++ linux/include/asm-sparc64/vga.h	Fri Apr 14 09:37:10 2000
@@ -7,6 +7,8 @@
 #ifndef _LINUX_ASM_VGA_H_
 #define _LINUX_ASM_VGA_H_
 
+#include <asm/types.h>
+
 #define VT_BUF_HAVE_RW
 
 static inline void scr_writew(u16 val, u16 *addr)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/ac97_codec.h linux/include/linux/ac97_codec.h
--- v2.3.99-pre5/linux/include/linux/ac97_codec.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/ac97_codec.h	Mon Apr 24 13:39:36 2000
@@ -32,7 +32,7 @@
 #define AC97_PCM_FRONT_DAC_RATE   0x002C       /* PCM Front DAC Rate */
 #define AC97_PCM_SURR_DAC_RATE    0x002E       /* PCM Surround DAC Rate */
 #define AC97_PCM_LFE_DAC_RATE     0x0030       /* PCM LFE DAC Rate */
-#define AC97_PCM_LR_DAC_RATE      0x0032       /* PCM LR DAC Rate */
+#define AC97_PCM_LR_ADC_RATE      0x0032       /* PCM LR ADC Rate */
 #define AC97_PCM_MIC_ADC_RATE     0x0034       /* PCM MIC ADC Rate */
 #define AC97_CENTER_LFE_MASTER    0x0036       /* Center + LFE Master Volume */
 #define AC97_SURROUND_MASTER      0x0038       /* Surround (Rear) Master Volume */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/atmdev.h linux/include/linux/atmdev.h
--- v2.3.99-pre5/linux/include/linux/atmdev.h	Mon Mar 27 08:08:31 2000
+++ linux/include/linux/atmdev.h	Wed Apr 26 15:32:25 2000
@@ -257,7 +257,7 @@
 #define ATM_ATMOPT_CLP	1	/* set CLP bit */
 
 
-typedef struct { unsigned short bits; } atm_vcc_flags_t;
+typedef struct { unsigned int bits; } atm_vcc_flags_t;
 
 
 struct atm_vcc {
@@ -286,7 +286,6 @@
 	struct sk_buff_head recvq;	/* receive queue */
 	struct k_atm_aal_stats *stats;	/* pointer to AAL stats group */
 	wait_queue_head_t sleep;	/* if socket is busy */
-	wait_queue_head_t wsleep;	/* if waiting for write buffer space */
 	struct sock	*sk;		/* socket backpointer */
 	struct atm_vcc	*prev,*next;
 	/* SVC part --- may move later ------------------------------------- */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.3.99-pre5/linux/include/linux/binfmts.h	Mon Mar 27 08:08:31 2000
+++ linux/include/linux/binfmts.h	Wed Apr 26 15:29:07 2000
@@ -54,6 +54,7 @@
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
 extern void compute_creds(struct linux_binprm *binprm);
 extern int do_coredump(long signr, struct pt_regs * regs);
+extern void set_binfmt(struct linux_binfmt *new);
 
 
 #if 0
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.3.99-pre5/linux/include/linux/blk.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/blk.h	Wed Apr 26 15:30:39 2000
@@ -53,6 +53,7 @@
 extern int ez_init(void);
 extern int bpcd_init(void);
 extern int ps2esdi_init(void);
+extern int jsfd_init(void);
 
 #if defined(CONFIG_ARCH_S390)
 extern int mdisk_init(void);
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.3.99-pre5/linux/include/linux/cdrom.h	Tue Mar  7 14:32:26 2000
+++ linux/include/linux/cdrom.h	Wed Apr 26 15:29:07 2000
@@ -905,7 +905,7 @@
 #endif
 	__u8     curlba[3];
 	__u8     nslots;
-	__u8 short slot_tablelen;
+	__u16 slot_tablelen;
 };
 
 struct cdrom_slot {
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.3.99-pre5/linux/include/linux/dcache.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/dcache.h	Wed Apr 26 15:29:06 2000
@@ -177,8 +177,8 @@
  * @entry: dentry to add
  * @inode: The inode to attach to this dentry
  *
- * This adds the entry to the hash queues and initializes "d_inode".
- * The entry was actually filled in earlier during "d_alloc()"
+ * This adds the entry to the hash queues and initializes @inode.
+ * The entry was actually filled in earlier during d_alloc().
  */
  
 static __inline__ void d_add(struct dentry * entry, struct inode * inode)
@@ -207,9 +207,9 @@
 
 /**
  *	dget	-	get a reference to a dentry
- *	@dentry: dentry to get a reference too
+ *	@dentry: dentry to get a reference to
  *
- *	Given a dentry or NULL pointer increment the reference count
+ *	Given a dentry or %NULL pointer increment the reference count
  *	if appropriate and return the dentry. A dentry will not be 
  *	destroyed when it has references.
  */
@@ -225,7 +225,7 @@
  *	d_unhashed -	is dentry hashed
  *	@dentry: entry to check
  *
- *	Returns true if the dentry passed is not currently hashed
+ *	Returns true if the dentry passed is not currently hashed.
  */
  
 static __inline__ int d_unhashed(struct dentry *dentry)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/file.h linux/include/linux/file.h
--- v2.3.99-pre5/linux/include/linux/file.h	Mon Jul 26 22:41:09 1999
+++ linux/include/linux/file.h	Mon Apr 24 16:10:27 2000
@@ -33,12 +33,12 @@
 	return file;
 }
 
-extern inline struct file * frip(unsigned int fd)
+extern inline struct file * frip(struct files_struct *files, unsigned int fd)
 {
 	struct file * file = NULL;
 
-	if (fd < current->files->max_fds)
-		file = xchg(&current->files->fd[fd], NULL);
+	if (fd < files->max_fds)
+		file = xchg(&files->fd[fd], NULL);
 	return file;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.99-pre5/linux/include/linux/fs.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/fs.h	Wed Apr 26 15:29:07 2000
@@ -20,7 +20,6 @@
 #include <linux/stat.h>
 #include <linux/cache.h>
 #include <linux/stddef.h>
-#include <linux/string.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
@@ -99,6 +98,7 @@
 #define MS_ODD_RENAME	32768	/* Temporary stuff; will go away as soon
 				  * as nfs_rename() will be cleaned up
 				  */
+#define S_DEAD		(1<<16)	/* removed, but still open directory */
 
 /*
  * Flags that can be altered by MS_REMOUNT
@@ -141,6 +141,7 @@
 #define IS_NOATIME(inode)	__IS_FLG(inode, MS_NOATIME)
 #define IS_NODIRATIME(inode)	__IS_FLG(inode, MS_NODIRATIME)
 
+#define IS_DEADDIR(inode)	((inode)->i_flags & S_DEAD)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -172,6 +173,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/string.h>
 #include <asm/semaphore.h>
 #include <asm/byteorder.h>
 
@@ -179,9 +181,9 @@
 #define UPDATE_ATIME(inode) update_atime (inode)
 
 extern void buffer_init(unsigned long);
-extern void inode_init(void);
+extern void inode_init(unsigned long);
 extern void file_table_init(void);
-extern void dcache_init(void);
+extern void dcache_init(unsigned long);
 
 /* bh state bits */
 #define BH_Uptodate	0	/* 1 if the buffer contains valid data */
@@ -336,8 +338,9 @@
 struct address_space;
 
 struct address_space_operations {
-	int (*writepage) (struct dentry *, struct page *);
+	int (*writepage)(struct file *, struct dentry *, struct page *);
 	int (*readpage)(struct dentry *, struct page *);
+	int (*sync_page)(struct page *);
 	int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
 	int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
 	/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
@@ -551,6 +554,8 @@
 	struct dentry *dentry;
 	struct vfsmount *mnt;
 	struct qstr last;
+	unsigned int flags;
+	int last_type;
 };
 
 #define FASYNC_MAGIC 0x4601
@@ -689,6 +694,11 @@
 	int (*revalidate) (kdev_t);
 };
 
+/*
+ * NOTE:
+ * read, write, poll, fsync, readv, writev can be called
+ *   without the big kernel lock held in all filesystems.
+ */
 struct file_operations {
 	loff_t (*llseek) (struct file *, loff_t, int);
 	ssize_t (*read) (struct file *, char *, size_t, loff_t *);
@@ -841,7 +851,8 @@
 extern int do_close(unsigned int, int);		/* yes, it's really unsigned */
 extern int do_truncate(struct dentry *, loff_t start);
 extern int get_unused_fd(void);
-extern void put_unused_fd(unsigned int);
+extern void __put_unused_fd(struct files_struct *, unsigned int); /* locked outside */
+extern void put_unused_fd(unsigned int);                          /* locked inside */
 
 extern struct file *filp_open(const char *, int, int);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
@@ -857,6 +868,7 @@
 extern struct block_device *bdget(dev_t);
 extern void bdput(struct block_device *);
 extern int blkdev_open(struct inode *, struct file *);
+extern int blkdev_close(struct inode * inode, struct file * filp);
 extern struct file_operations def_blk_fops;
 extern struct file_operations def_fifo_fops;
 extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
@@ -878,7 +890,6 @@
 extern void make_bad_inode(struct inode *);
 extern int is_bad_inode(struct inode *);
 
-extern struct file_operations connecting_fifo_fops;
 extern struct file_operations read_fifo_fops;
 extern struct file_operations write_fifo_fops;
 extern struct file_operations rdwr_fifo_fops;
@@ -947,7 +958,6 @@
 #define invalidate_buffers(dev)	__invalidate_buffers((dev), 0)
 #define destroy_buffers(dev)	__invalidate_buffers((dev), 1)
 extern void __invalidate_buffers(kdev_t dev, int);
-extern int floppy_is_wp(int);
 extern void sync_inodes(kdev_t);
 extern void write_inode_now(struct inode *);
 extern void sync_dev(kdev_t);
@@ -991,10 +1001,14 @@
  */
 #define LOOKUP_FOLLOW		(1)
 #define LOOKUP_DIRECTORY	(2)
-#define LOOKUP_SLASHOK		(4)
-#define LOOKUP_CONTINUE		(8)
-#define LOOKUP_POSITIVE		(16)
-#define LOOKUP_PARENT		(32)
+#define LOOKUP_CONTINUE		(4)
+#define LOOKUP_POSITIVE		(8)
+#define LOOKUP_PARENT		(16)
+#define LOOKUP_NOALT		(32)
+/*
+ * Type of the last component on LOOKUP_PARENT
+ */
+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT };
 
 /*
  * "descriptor" for what we're up to with a read for sendfile().
@@ -1014,9 +1028,12 @@
 
 typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
 
+/* needed for stackable file system support */
+extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
+
 extern struct dentry * lookup_dentry(const char *, unsigned int);
 extern int walk_init(const char *, unsigned, struct nameidata *);
-extern int walk_name(const char *, unsigned, struct nameidata *);
+extern int walk_name(const char *, struct nameidata *);
 extern struct dentry * lookup_one(const char *, struct dentry *);
 extern struct dentry * __namei(const char *, unsigned int);
 
@@ -1071,12 +1088,15 @@
 
 /* Generic buffer handling for block filesystems.. */
 extern int block_flushpage(struct page *, unsigned long);
+extern int block_fsync(struct file *filp, struct dentry *dentry);
 extern int block_symlink(struct inode *, const char *, int);
 extern int block_write_full_page(struct page*, get_block_t*);
 extern int block_read_full_page(struct page*, get_block_t*);
 extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
 extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
 				unsigned long *);
+extern int block_sync_page(struct page *);
+
 int generic_block_bmap(struct address_space *, long, get_block_t *);
 int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/fs_struct.h linux/include/linux/fs_struct.h
--- v2.3.99-pre5/linux/include/linux/fs_struct.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/fs_struct.h	Mon Apr 24 13:41:10 2000
@@ -0,0 +1,59 @@
+#ifndef _LINUX_FS_STRUCT_H
+#define _LINUX_FS_STRUCT_H
+#ifdef __KERNEL__
+
+struct fs_struct {
+	atomic_t count;
+	int umask;
+	struct dentry * root, * pwd, * altroot;
+	struct vfsmount * rootmnt, * pwdmnt, * altrootmnt;
+};
+
+#define INIT_FS { \
+	ATOMIC_INIT(1), \
+	0022, \
+	NULL, NULL, NULL, NULL, NULL, NULL \
+}
+
+extern void exit_fs(struct task_struct *);
+extern void set_fs_altroot(void);
+
+/*
+ * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
+ * It can block. Requires the big lock held.
+ */
+
+static inline void set_fs_root(struct fs_struct *fs,
+	struct vfsmount *mnt,
+	struct dentry *dentry)
+{
+	struct dentry *old_root = fs->root;
+	struct vfsmount *old_rootmnt = fs->rootmnt;
+	fs->rootmnt = mntget(mnt);
+	fs->root = dget(dentry);
+	dput(old_root);
+	mntput(old_rootmnt);
+}
+
+/*
+ * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
+ * It can block. Requires the big lock held.
+ */
+
+static inline void set_fs_pwd(struct fs_struct *fs,
+	struct vfsmount *mnt,
+	struct dentry *dentry)
+{
+	struct dentry *old_pwd = fs->pwd;
+	struct vfsmount *old_pwdmnt = fs->pwdmnt;
+	fs->pwdmnt = mntget(mnt);
+	fs->pwd = dget(dentry);
+	dput(old_pwd);
+	mntput(old_pwdmnt);
+}
+
+struct fs_struct *copy_fs_struct(struct fs_struct *old);
+void put_fs_struct(struct fs_struct *fs);
+
+#endif
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v2.3.99-pre5/linux/include/linux/hdreg.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/hdreg.h	Wed Apr 26 15:29:07 2000
@@ -96,6 +96,8 @@
 #define SMART_AUTOSAVE		0xd2
 #define SMART_SAVE		0xd3
 #define SMART_IMMEDIATE_OFFLINE	0xd4
+#define SMART_READ_LOG_SECTOR	0xd5
+#define SMART_WRITE_LOG_SECTOR	0xd6
 #define SMART_ENABLE		0xd8
 #define SMART_DISABLE		0xd9
 #define SMART_STATUS		0xda
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/hdsmart.h linux/include/linux/hdsmart.h
--- v2.3.99-pre5/linux/include/linux/hdsmart.h	Thu May 13 11:00:09 1999
+++ linux/include/linux/hdsmart.h	Thu Apr 13 22:54:26 2000
@@ -1,61 +1,139 @@
-#ifndef _LINUX_HDSMART_H
-#define _LINUX_HDSMART_H
-
 /*
- * This file contains some defines for the AT-hd-controller.
- * Various sources.  
+ * linux/include/linux/hdsmart.h
+ *
+ * Copyright (C) 1999-2000	Michael Cornwell <cornwell@acm.org>
+ * Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define NR_ATTRIBUTES	30
+#ifndef _LINUX_HDSMART_H
+#define _LINUX_HDSMART_H
 
-typedef struct threshold_s {
-	unsigned char	id;
-	unsigned char	threshold;
-	unsigned char	reserved[10];
-} __attribute__ ((packed)) threshold_t;
-
-typedef struct thresholds_s {
-	unsigned short	revision;
-	threshold_t	thresholds[NR_ATTRIBUTES];
-	unsigned char	reserved[18];
-	unsigned char	vendor[131];
-	unsigned char	checksum;
-} __attribute__ ((packed)) thresholds_t;
-
-typedef struct value_s {
-	unsigned char	id;
-	unsigned short	status;
-	unsigned char	value;
-	unsigned char	vendor[8];
-} __attribute__ ((packed)) value_t;
-
-typedef struct values_s {
-	unsigned short	revision;
-	value_t		values[NR_ATTRIBUTES];
-	unsigned char	offline_status;
-	unsigned char	vendor1;
-	unsigned short	offline_timeout;
-	unsigned char	vendor2;
-	unsigned char	offline_capability;
-	unsigned short	smart_capability;
-	unsigned char	reserved[16];
-	unsigned char	vendor[125];
-	unsigned char	checksum;
-} __attribute__ ((packed)) values_t;
+/* smart_attribute is the vendor specific in SFF-8035 spec */
+struct ata_smart_attribute {
+	unsigned char				id;
+	unsigned short				status_flag;
+	unsigned char				normalized;
+	unsigned char				worse_normal;
+	unsigned char				raw[6];
+	unsigned char				reserv;
+} __attribute__ ((packed));
+
+/* smart_values is format of the read drive Atrribute command */
+struct ata_smart_values {
+	unsigned short				revnumber;
+	struct ata_smart_attribute		vendor_attributes [30];
+        unsigned char				offline_data_collection_status;
+        unsigned char				self_test_exec_status;
+	unsigned short				total_time_to_complete_off_line;
+	unsigned char				vendor_specific_366;
+	unsigned char				offline_data_collection_capability;
+	unsigned short				smart_capability;
+	unsigned char				errorlog_capability;
+	unsigned char				vendor_specific_371;
+	unsigned char				short_test_completion_time;
+	unsigned char				extend_test_completion_time;
+	unsigned char				reserved_374_385 [12];
+	unsigned char				vendor_specific_386_509 [125];
+	unsigned char				chksum;
+} __attribute__ ((packed));
+
+/* Smart Threshold data structures */
+/* Vendor attribute of SMART Threshold */
+struct ata_smart_threshold_entry {
+	unsigned char				id;
+	unsigned char				normalized_threshold;
+	unsigned char				reserved[10];
+} __attribute__ ((packed));
+
+/* Format of Read SMART THreshold Command */
+struct ata_smart_thresholds {
+	unsigned short				revnumber;
+	struct ata_smart_threshold_entry	thres_entries[30];
+	unsigned char				reserved[149];
+	unsigned char				chksum;
+} __attribute__ ((packed));
+
+struct ata_smart_errorlog_command_struct {
+	unsigned char				devicecontrolreg;
+	unsigned char				featuresreg;
+	unsigned char				sector_count;
+	unsigned char				sector_number;
+	unsigned char				cylinder_low;
+	unsigned char				cylinder_high;
+	unsigned char				drive_head;
+	unsigned char				commandreg;
+	unsigned int				timestamp;
+} __attribute__ ((packed));
+
+struct ata_smart_errorlog_error_struct {
+	unsigned char				error_condition;
+	unsigned char				extended_error[14];
+	unsigned char				state;
+	unsigned short				timestamp;
+} __attribute__ ((packed));
+
+struct ata_smart_errorlog_struct {
+	struct ata_smart_errorlog_command_struct	commands[6];
+	struct ata_smart_errorlog_error_struct		error_struct;
+}  __attribute__ ((packed));
+
+struct ata_smart_errorlog {
+	unsigned char				revnumber;
+	unsigned char				error_log_pointer;
+	struct ata_smart_errorlog_struct	errorlog_struct[5];
+	unsigned short				ata_error_count;
+	unsigned short				non_fatal_count;
+	unsigned short				drive_timeout_count;
+	unsigned char				reserved[53];
+} __attribute__ ((packed));
+
+struct ata_smart_selftestlog_struct {
+	unsigned char				selftestnumber;
+	unsigned char				selfteststatus;
+	unsigned short				timestamp;
+	unsigned char				selftestfailurecheckpoint;
+	unsigned int				lbafirstfailure;
+	unsigned char				vendorspecific[15];
+} __attribute__ ((packed));
+
+struct ata_smart_selftestlog {
+	unsigned short				revnumber;
+	struct ata_smart_selftestlog_struct	selftest_struct[21];
+	unsigned char				vendorspecific[2];
+	unsigned char				mostrecenttest;
+	unsigned char				resevered[2];
+	unsigned char				chksum;
+} __attribute__ ((packed));
 
 #if !defined(__KERNEL__) || defined(_IDE_DISK_C)
- 
-#define NR_OFFLINE_TEXTS	5
-struct {
-	unsigned char	value;
-	char		*text;
-} offline_status_text[NR_OFFLINE_TEXTS] = {
-	{ 0x00, "NeverStarted" },
-	{ 0x02, "Completed" },
-	{ 0x04, "Suspended" },
-	{ 0x05, "Aborted" },
-	{ 0x06, "Failed" }
-};
+/* smartctl version number */
+#define VERSION_MAJOR           		1
+#define VERSION_MINOR           		2
+
+/* Number of ata device to scan */
+int numdevices;
+
+/* how often SMART is checks in seconds */
+int checktime = 1800;
+
+typedef struct atadevices_s {
+	int					fd;
+	char					devicename[14];
+	int					selftest;
+	struct hd_driveid			drive;
+	struct ata_smart_values			smartval;
+	struct ata_smart_thresholds		smartthres;
+} atadevices_t;
+
 #endif /* !defined(__KERNEL__) || defined(_IDE_DISK_C) */
 
 #endif	/* _LINUX_HDSMART_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/i2o-dev.h linux/include/linux/i2o-dev.h
--- v2.3.99-pre5/linux/include/linux/i2o-dev.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/i2o-dev.h	Wed Apr 12 09:38:53 2000
@@ -0,0 +1,397 @@
+/*
+ * I2O user space accessible structures/APIs
+ * 
+ * (c) Copyright 1999, 2000 Red Hat Software
+ *
+ * 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 header file defines the I2O APIs that are available to both
+ * the kernel and user level applications.  Kernel specific structures
+ * are defined in i2o_osm. OSMs should include _only_ i2o_osm.h which
+ * automatically includs this file.
+ *
+ */
+
+#ifndef _I2O_DEV_H
+#define _I2O_DEV_H
+
+/* How many controllers are we allowing */
+#define MAX_I2O_CONTROLLERS	32
+
+#include <linux/ioctl.h>
+
+/*
+ * I2O Control IOCTLs and structures
+ */
+#define I2O_MAGIC_NUMBER	'i'
+#define I2OGETIOPS		_IOR(I2O_MAGIC_NUMBER,0,u8[MAX_I2O_CONTROLLERS])
+#define I2OHRTGET		_IOWR(I2O_MAGIC_NUMBER,1,struct i2o_cmd_hrtlct)
+#define I2OLCTGET		_IOWR(I2O_MAGIC_NUMBER,2,struct i2o_cmd_hrtlct)
+#define I2OPARMSET		_IOWR(I2O_MAGIC_NUMBER,3,struct i2o_cmd_psetget)
+#define I2OPARMGET		_IOWR(I2O_MAGIC_NUMBER,4,struct i2o_cmd_psetget)
+#define I2OSWDL			_IOWR(I2O_MAGIC_NUMBER,5,struct i2o_sw_xfer)
+#define I2OSWUL			_IOWR(I2O_MAGIC_NUMBER,6,struct i2o_sw_xfer)
+#define I2OSWDEL		_IOWR(I2O_MAGIC_NUMBER,7,struct i2o_sw_xfer)
+#define I2OVALIDATE		_IOR(I2O_MAGIC_NUMBER,8,u32)
+#define I2OHTML			_IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html)
+#define I2OEVTREG		_IOW(I2O_MAGIC_NUMBER,10,struct i2o_evt_id)
+#define I2OEVTGET		_IOR(I2O_MAGIC_NUMBER,11,struct i2o_evt_info)
+
+struct i2o_cmd_hrtlct
+{
+	unsigned int iop;	/* IOP unit number */
+	void *resbuf;		/* Buffer for result */
+	unsigned int *reslen;	/* Buffer length in bytes */
+};
+
+struct i2o_cmd_psetget
+{
+	unsigned int iop;	/* IOP unit number */
+	unsigned int tid;	/* Target device TID */
+	void *opbuf;		/* Operation List buffer */
+	unsigned int oplen;	/* Operation List buffer length in bytes */
+	void *resbuf;		/* Result List buffer */
+	unsigned int *reslen;	/* Result List buffer length in bytes */
+};
+
+struct i2o_sw_xfer
+{
+	unsigned int iop;	/* IOP unit number */
+	unsigned char flags;	/* Flags field */
+	unsigned char sw_type;	/* Software type */
+	unsigned int sw_id;	/* Software ID */
+	void *buf;		/* Pointer to software buffer */
+	unsigned int *swlen;	/* Length of software data */
+	unsigned int *maxfrag;	/* Maximum fragment count */
+        unsigned int *curfrag;	/* Current fragment count */
+};
+
+struct i2o_html
+{
+	unsigned int iop;	/* IOP unit number */
+	unsigned int tid;	/* Target device ID */
+	unsigned int page;	/* HTML page */
+	void *resbuf;		/* Buffer for reply HTML page */
+	unsigned int *reslen;	/* Length in bytes of reply buffer */
+	void *qbuf;		/* Pointer to HTTP query string */
+	unsigned int qlen;	/* Length in bytes of query string buffer */
+};
+
+#define I2O_EVT_Q_LEN 32
+
+struct i2o_evt_id
+{
+	unsigned int iop;
+	unsigned int tid;
+	unsigned int evt_mask;
+};
+
+/* Event data size = frame size - message header + evt indicator */
+#define I2O_EVT_DATA_SIZE 88
+
+struct i2o_evt_info
+{
+	struct i2o_evt_id id;
+	unsigned char evt_data[I2O_EVT_DATA_SIZE];
+ 	unsigned int data_size;
+};
+
+struct i2o_evt_get
+{
+	struct i2o_evt_info info;
+	int pending;
+	int lost;
+};
+
+
+/**************************************************************************
+ * HRT related constants and structures
+ **************************************************************************/
+#define I2O_BUS_LOCAL	0
+#define I2O_BUS_ISA	1
+#define I2O_BUS_EISA	2
+#define I2O_BUS_MCA	3
+#define I2O_BUS_PCI	4
+#define I2O_BUS_PCMCIA	5
+#define I2O_BUS_NUBUS	6
+#define I2O_BUS_CARDBUS	7
+#define I2O_BUS_UNKNOWN	0x80
+
+#ifndef __KERNEL__
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#endif /* __KERNEL__ */
+
+typedef struct _i2o_pci_bus {
+	u8 PciFunctionNumber;
+	u8 PciDeviceNumber;
+	u8 PciBusNumber;
+	u8 reserved;
+	u16 PciVendorID;
+	u16 PciDeviceID;
+} i2o_pci_bus;
+
+typedef struct _i2o_local_bus {
+	u16 LbBaseIOPort;
+	u16 reserved;
+	u32 LbBaseMemoryAddress;
+} i2o_local_bus;
+
+typedef struct _i2o_isa_bus {
+	u16 IsaBaseIOPort;
+	u8 CSN;
+	u8 reserved;
+	u32 IsaBaseMemoryAddress;
+} i2o_isa_bus;
+
+typedef struct _i2o_eisa_bus_info {
+	u16 EisaBaseIOPort;
+	u8 reserved;
+	u8 EisaSlotNumber;
+	u32 EisaBaseMemoryAddress;
+} i2o_eisa_bus;
+
+typedef struct _i2o_mca_bus {
+	u16 McaBaseIOPort;
+	u8 reserved;
+	u8 McaSlotNumber;
+	u32 McaBaseMemoryAddress;
+} i2o_mca_bus;
+
+typedef struct _i2o_other_bus {
+	u16 BaseIOPort;
+	u16 reserved;
+	u32 BaseMemoryAddress;
+} i2o_other_bus;
+
+typedef struct _i2o_hrt_entry {
+	u32 adapter_id;
+	u32 parent_tid:12;
+	u32 state:4;
+	u32 bus_num:8;
+	u32 bus_type:8;
+	union {
+		i2o_pci_bus pci_bus;
+		i2o_local_bus local_bus;
+		i2o_isa_bus isa_bus;
+		i2o_eisa_bus eisa_bus;
+		i2o_mca_bus mca_bus;
+		i2o_other_bus other_bus;
+	} bus;
+} i2o_hrt_entry;
+
+typedef struct _i2o_hrt {
+	u16 num_entries;
+	u8 entry_len;
+	u8 hrt_version;
+	u32 change_ind;
+	i2o_hrt_entry hrt_entry[1];
+} i2o_hrt;
+
+typedef struct _i2o_lct_entry {
+	u32 entry_size:16;
+	u32 tid:12;
+	u32 reserved:4;
+	u32 change_ind;
+	u32 device_flags;
+	u32 class_id:12;
+	u32 version:4;
+	u32 vendor_id:16;
+	u32 sub_class;
+	u32 user_tid:12;
+	u32 parent_tid:12;
+	u32 bios_info:8;
+	u8 identity_tag[8];
+	u32 event_capabilities;
+} i2o_lct_entry;
+
+typedef struct _i2o_lct {
+	u32 table_size:16;
+	u32 boot_tid:12;
+	u32 lct_ver:4;
+	u32 iop_flags;
+	u32 change_ind;
+	i2o_lct_entry lct_entry[1];
+} i2o_lct;
+
+typedef struct _i2o_status_block {
+	u16 org_id;
+	u16 reserved;
+	u16 iop_id:12;
+	u16 reserved1:4;
+	u16 host_unit_id;
+	u16 segment_number:12;
+	u16 i2o_version:4;
+	u8 iop_state;
+	u8 msg_type;
+	u16 inbound_frame_size;
+	u8 init_code;	
+	u8 reserved2;
+	u32 max_inbound_frames;
+	u32 cur_inbound_frames;
+	u32 max_outbound_frames;
+	char product_id[24];	
+	u32 expected_lct_size;
+	u32 iop_capabilities;
+	u32 desired_mem_size;
+	u32 current_mem_size;
+	u32 current_mem_base;
+	u32 desired_io_size;
+	u32 current_io_size;
+	u32 current_io_base;
+	u32 reserved3:24;
+	u32 cmd_status:8;
+} i2o_status_block;
+ 
+/* Event indicator mask flags */
+#define I2O_EVT_IND_STATE_CHANGE		0x80000000
+#define I2O_EVT_IND_GENERAL_WARNING		0x40000000
+#define I2O_EVT_IND_CONFIGURATION_FLAG		0x20000000
+#define I2O_EVT_IND_LOCK_RELEASE		0x10000000
+#define I2O_EVT_IND_CAPABILITY_CHANGE		0x08000000
+#define I2O_EVT_IND_DEVICE_RESET		0x04000000
+#define I2O_EVT_IND_EVT_MASK_MODIFIED		0x02000000
+#define I2O_EVT_IND_FIELD_MODIFIED		0x01000000
+#define I2O_EVT_IND_VENDOR_EVT			0x00800000
+#define I2O_EVT_IND_DEVICE_STATE		0x00400000
+
+/* Executive event indicitors */
+#define I2O_EVT_IND_EXEC_RESOURCE_LIMITS	0x00000001
+#define I2O_EVT_IND_EXEC_CONNECTION_FAIL	0x00000002
+#define I2O_EVT_IND_EXEC_ADAPTER_FAULT		0x00000004
+#define I2O_EVT_IND_EXEC_POWER_FAIL		0x00000008
+#define I2O_EVT_IND_EXEC_RESET_PENDING		0x00000010
+#define I2O_EVT_IND_EXEC_RESET_IMMINENT		0x00000020
+#define I2O_EVT_IND_EXEC_HW_FAIL		0x00000040
+#define I2O_EVT_IND_EXEC_XCT_CHANGE		0x00000080
+#define I2O_EVT_IND_EXEC_NEW_LCT_ENTRY		0x00000100
+#define I2O_EVT_IND_EXEC_MODIFIED_LCT		0x00000200
+#define I2O_EVT_IND_EXEC_DDM_AVAILABILITY	0x00000400
+
+/* Random Block Storage Event Indicators */
+#define I2O_EVT_IND_BSA_VOLUME_LOAD		0x00000001
+#define I2O_EVT_IND_BSA_VOLUME_UNLOAD		0x00000002
+#define I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ	0x00000004
+#define I2O_EVT_IND_BSA_CAPACITY_CHANGE		0x00000008
+#define I2O_EVT_IND_BSA_SCSI_SMART		0x00000010
+
+/* Event data for generic events */
+#define I2O_EVT_STATE_CHANGE_NORMAL		0x00
+#define I2O_EVT_STATE_CHANGE_SUSPENDED		0x01
+#define I2O_EVT_STATE_CHANGE_RESTART		0x02
+#define I2O_EVT_STATE_CHANGE_NA_RECOVER		0x03
+#define I2O_EVT_STATE_CHANGE_NA_NO_RECOVER	0x04
+#define I2O_EVT_STATE_CHANGE_QUIESCE_REQUEST	0x05
+#define I2O_EVT_STATE_CHANGE_FAILED		0x10
+#define I2O_EVT_STATE_CHANGE_FAULTED		0x11
+
+#define I2O_EVT_GEN_WARNING_NORMAL		0x00
+#define I2O_EVT_GEN_WARNING_ERROR_THRESHOLD	0x01
+#define I2O_EVT_GEN_WARNING_MEDIA_FAULT		0x02
+
+#define I2O_EVT_CAPABILITY_OTHER		0x01
+#define I2O_EVT_CAPABILITY_CHANGED		0x02
+
+#define I2O_EVT_SENSOR_STATE_CHANGED		0x01
+
+/*
+ *	I2O classes / subclasses
+ */
+
+/*  Class ID and Code Assignments
+ *  (LCT.ClassID.Version field)
+ */
+#define    I2O_CLASS_VERSION_10                        0x00
+#define    I2O_CLASS_VERSION_11                        0x01
+
+/*  Class code names
+ *  (from v1.5 Table 6-1 Class Code Assignments.)
+ */
+ 
+#define    I2O_CLASS_EXECUTIVE                         0x000
+#define    I2O_CLASS_DDM                               0x001
+#define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
+#define    I2O_CLASS_SEQUENTIAL_STORAGE                0x011
+#define    I2O_CLASS_LAN                               0x020
+#define    I2O_CLASS_WAN                               0x030
+#define    I2O_CLASS_FIBRE_CHANNEL_PORT                0x040
+#define    I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL          0x041
+#define    I2O_CLASS_SCSI_PERIPHERAL                   0x051
+#define    I2O_CLASS_ATE_PORT                          0x060
+#define    I2O_CLASS_ATE_PERIPHERAL                    0x061
+#define    I2O_CLASS_FLOPPY_CONTROLLER                 0x070
+#define    I2O_CLASS_FLOPPY_DEVICE                     0x071
+#define    I2O_CLASS_BUS_ADAPTER_PORT                  0x080
+#define    I2O_CLASS_PEER_TRANSPORT_AGENT              0x090
+#define    I2O_CLASS_PEER_TRANSPORT                    0x091
+
+/* 
+ *  Rest of 0x092 - 0x09f reserved for peer-to-peer classes
+ */
+ 
+#define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
+
+/* 
+ *  Subclasses
+ */
+
+#define    I2O_SUBCLASS_i960                           0x001
+#define    I2O_SUBCLASS_HDM                            0x020
+#define    I2O_SUBCLASS_ISM                            0x021
+ 
+/* Operation functions */
+
+#define I2O_PARAMS_FIELD_GET	0x0001
+#define I2O_PARAMS_LIST_GET	0x0002
+#define I2O_PARAMS_MORE_GET	0x0003
+#define I2O_PARAMS_SIZE_GET	0x0004
+#define I2O_PARAMS_TABLE_GET	0x0005
+#define I2O_PARAMS_FIELD_SET	0x0006
+#define I2O_PARAMS_LIST_SET	0x0007
+#define I2O_PARAMS_ROW_ADD	0x0008
+#define I2O_PARAMS_ROW_DELETE	0x0009
+#define I2O_PARAMS_TABLE_CLEAR	0x000A
+
+/*
+ * I2O serial number conventions / formats 
+ * (circa v1.5)
+ */
+
+#define    I2O_SNFORMAT_UNKNOWN                        0
+#define    I2O_SNFORMAT_BINARY                         1
+#define    I2O_SNFORMAT_ASCII                          2
+#define    I2O_SNFORMAT_UNICODE                        3
+#define    I2O_SNFORMAT_LAN48_MAC                      4
+#define    I2O_SNFORMAT_WAN                            5
+
+/* 
+ * Plus new in v2.0 (Yellowstone pdf doc)
+ */
+
+#define    I2O_SNFORMAT_LAN64_MAC                      6
+#define    I2O_SNFORMAT_DDM                            7
+#define    I2O_SNFORMAT_IEEE_REG64                     8
+#define    I2O_SNFORMAT_IEEE_REG128                    9
+#define    I2O_SNFORMAT_UNKNOWN2                       0xff
+
+/*
+ *	I2O Get Status State values 
+ */
+
+#define	ADAPTER_STATE_INITIALIZING		0x01
+#define	ADAPTER_STATE_RESET			0x02
+#define	ADAPTER_STATE_HOLD			0x04
+#define 	ADAPTER_STATE_READY			0x05
+#define	ADAPTER_STATE_OPERATIONAL		0x08
+#define	ADAPTER_STATE_FAILED			0x10
+#define	ADAPTER_STATE_FAULTED			0x11
+	
+#endif /* _I2O_DEV_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.3.99-pre5/linux/include/linux/i2o.h	Tue Jan 11 22:31:44 2000
+++ linux/include/linux/i2o.h	Wed Apr 12 09:38:53 2000
@@ -1,281 +1,33 @@
+/*
+ * I2O kernel space accessible structures/APIs
+ * 
+ * (c) Copyright 1999, 2000 Red Hat Software
+ *
+ * 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 header file defined the I2O APIs/structures for use by 
+ * the I2O kernel modules.
+ *
+ */
+
 #ifndef _I2O_H
 #define _I2O_H
+#ifdef __KERNEL__	/* This file to be included by kernel only */
 
-/*
- *	Tunable parameters first
- */
+#include <linux/i2o-dev.h>
 
 /* How many different OSM's are we allowing */ 
 #define MAX_I2O_MODULES		64
-/* How many controllers are we allowing */
-#define MAX_I2O_CONTROLLERS	32
-
-#include <linux/ioctl.h>
-
-/*
- * I2O Control IOCTLs and structures
- */
-#define I2O_MAGIC_NUMBER	'i'
-#define I2OGETIOPS		_IOR(I2O_MAGIC_NUMBER,0,u8[MAX_I2O_CONTROLLERS])
-#define I2OHRTGET		_IOWR(I2O_MAGIC_NUMBER,1,struct i2o_cmd_hrtlct)
-#define I2OLCTGET		_IOWR(I2O_MAGIC_NUMBER,2,struct i2o_cmd_hrtlct)
-#define I2OPARMSET		_IOWR(I2O_MAGIC_NUMBER,3,struct i2o_cmd_psetget)
-#define I2OPARMGET		_IOWR(I2O_MAGIC_NUMBER,4,struct i2o_cmd_psetget)
-#define I2OSWDL			_IOWR(I2O_MAGIC_NUMBER,5,struct i2o_sw_xfer)
-#define I2OSWUL			_IOWR(I2O_MAGIC_NUMBER,6,struct i2o_sw_xfer)
-#define I2OSWDEL		_IOWR(I2O_MAGIC_NUMBER,7,struct i2o_sw_xfer)
-#define I2OVALIDATE		_IOR(I2O_MAGIC_NUMBER,8,u32)
-#define I2OHTML			_IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html)
-#define I2OEVTREG		_IOW(I2O_MAGIC_NUMBER,10,struct i2o_evt_id)
-#define I2OEVTGET		_IOR(I2O_MAGIC_NUMBER,11,struct i2o_evt_info)
-
-struct i2o_cmd_hrtlct
-{
-	unsigned int iop;	/* IOP unit number */
-	void *resbuf;		/* Buffer for result */
-	unsigned int *reslen;	/* Buffer length in bytes */
-};
-
-struct i2o_cmd_psetget
-{
-	unsigned int iop;	/* IOP unit number */
-	unsigned int tid;	/* Target device TID */
-	void *opbuf;		/* Operation List buffer */
-	unsigned int oplen;	/* Operation List buffer length in bytes */
-	void *resbuf;		/* Result List buffer */
-	unsigned int *reslen;	/* Result List buffer length in bytes */
-};
-
-struct i2o_sw_xfer
-{
-	unsigned int iop;	/* IOP unit number */
-	unsigned char flags;	/* Flags field */
-	unsigned char sw_type;	/* Software type */
-	unsigned int sw_id;	/* Software ID */
-	void *buf;		/* Pointer to software buffer */
-	unsigned int *swlen;	/* Length of software data */
-	unsigned int *maxfrag;	/* Maximum fragment count */
-        unsigned int *curfrag;	/* Current fragment count */
-};
-
-struct i2o_html
-{
-	unsigned int iop;	/* IOP unit number */
-	unsigned int tid;	/* Target device ID */
-	unsigned int page;	/* HTML page */
-	void *resbuf;		/* Buffer for reply HTML page */
-	unsigned int *reslen;	/* Length in bytes of reply buffer */
-	void *qbuf;		/* Pointer to HTTP query string */
-	unsigned int qlen;	/* Length in bytes of query string buffer */
-};
-
-#define I2O_EVT_Q_LEN 32
-
-struct i2o_evt_id
-{
-	unsigned int iop;
-	unsigned int tid;
-	unsigned int evt_mask;
-};
-
-//
-// Event data size = frame size - message header + evt indicator
-#define I2O_EVT_DATA_SIZE 88
-
-struct i2o_evt_info
-{
-	struct i2o_evt_id id;
-	unsigned char evt_data[I2O_EVT_DATA_SIZE];
- 	unsigned int data_size;
-};
-
-struct i2o_evt_get
-{
-	struct i2o_evt_info info;
-	int pending;
-	int lost;
-};
-
-
-/**************************************************************************
- * HRT related constants and structures
- **************************************************************************/
-#define I2O_BUS_LOCAL	0
-#define I2O_BUS_ISA	1
-#define I2O_BUS_EISA	2
-#define I2O_BUS_MCA	3
-#define I2O_BUS_PCI	4
-#define I2O_BUS_PCMCIA	5
-#define I2O_BUS_NUBUS	6
-#define I2O_BUS_CARDBUS	7
-#define I2O_BUS_UNKNOWN	0x80
-
-#ifndef __KERNEL__
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-#endif /* __KERNEL__ */
-
-typedef struct _i2o_pci_bus {
-	u8 PciFunctionNumber;
-	u8 PciDeviceNumber;
-	u8 PciBusNumber;
-	u8 reserved;
-	u16 PciVendorID;
-	u16 PciDeviceID;
-} i2o_pci_bus;
-
-typedef struct _i2o_local_bus {
-	u16 LbBaseIOPort;
-	u16 reserved;
-	u32 LbBaseMemoryAddress;
-} i2o_local_bus;
-
-typedef struct _i2o_isa_bus {
-	u16 IsaBaseIOPort;
-	u8 CSN;
-	u8 reserved;
-	u32 IsaBaseMemoryAddress;
-} i2o_isa_bus;
-
-typedef struct _i2o_eisa_bus_info {
-	u16 EisaBaseIOPort;
-	u8 reserved;
-	u8 EisaSlotNumber;
-	u32 EisaBaseMemoryAddress;
-} i2o_eisa_bus;
-
-typedef struct _i2o_mca_bus {
-	u16 McaBaseIOPort;
-	u8 reserved;
-	u8 McaSlotNumber;
-	u32 McaBaseMemoryAddress;
-} i2o_mca_bus;
-
-typedef struct _i2o_other_bus {
-	u16 BaseIOPort;
-	u16 reserved;
-	u32 BaseMemoryAddress;
-} i2o_other_bus;
-
-typedef struct _i2o_hrt_entry {
-	u32 adapter_id;
-	u32 parent_tid:12;
-	u32 state:4;
-	u32 bus_num:8;
-	u32 bus_type:8;
-	union {
-		i2o_pci_bus pci_bus;
-		i2o_local_bus local_bus;
-		i2o_isa_bus isa_bus;
-		i2o_eisa_bus eisa_bus;
-		i2o_mca_bus mca_bus;
-		i2o_other_bus other_bus;
-	} bus;
-} i2o_hrt_entry;
-
-typedef struct _i2o_hrt {
-	u16 num_entries;
-	u8 entry_len;
-	u8 hrt_version;
-	u32 change_ind;
-	i2o_hrt_entry hrt_entry[1];
-} i2o_hrt;
-
-typedef struct _i2o_lct_entry {
-	u32 entry_size:16;
-	u32 tid:12;
-	u32 reserved:4;
-	u32 change_ind;
-	u32 device_flags;
-	u32 class_id:12;
-	u32 version:4;
-	u32 vendor_id:16;
-	u32 sub_class;
-	u32 user_tid:12;
-	u32 parent_tid:12;
-	u32 bios_info:8;
-	u8 identity_tag[8];
-	u32 event_capabilities;
-} i2o_lct_entry;
-
-typedef struct _i2o_lct {
-	u32 table_size:16;
-	u32 boot_tid:12;
-	u32 lct_ver:4;
-	u32 iop_flags;
-	u32 current_change_ind;
-	i2o_lct_entry lct_entry[1];
-} i2o_lct;
-
-typedef struct _i2o_status_block {
-	u16 org_id;
-	u16 reserved;
-	u16 iop_id:12;
-	u16 reserved1:4;
-	u16 host_unit_id;
-	u16 segment_number:12;
-	u16 i2o_version:4;
-	u8 iop_state;
-	u8 msg_type;
-	u16 inbound_frame_size;
-	u8 init_code;	
-	u8 reserved2;
-	u32 max_inbound_frames;
-	u32 cur_inbound_frames;
-	u32 max_outbound_frames;
-	char product_id[24];	
-	u32 expected_lct_size;
-	u32 iop_capabilities;
-	u32 desired_mem_size;
-	u32 current_mem_size;
-	u32 current_mem_base;
-	u32 desired_io_size;
-	u32 current_io_size;
-	u32 current_io_base;
-	u32 reserved3:24;
-	u32 cmd_status:8;
-} i2o_status_block;
- 
-/* Event indicator mask flags */
-#define I2O_EVT_IND_STATE_CHANGE		0x80000000
-#define I2O_EVT_IND_GENERAL_WARNING		0x40000000
-#define I2O_EVT_IND_CONFIGURATION_FLAG		0x20000000
-#define I2O_EVT_IND_LOCK_RELEASE		0x10000000
-#define I2O_EVT_IND_CAPABILITY_CHANGE		0x08000000
-#define I2O_EVT_IND_DEVICE_RESET		0x04000000
-#define I2O_EVT_IND_EVT_MASK_MODIFIED		0x02000000
-#define I2O_EVT_IND_FIELD_MODIFIED		0x01000000
-#define I2O_EVT_IND_VENDOR_EVT			0x00800000
-#define I2O_EVT_IND_DEVICE_STATE		0x00400000
-
-/* Event data for generic events */
-#define I2O_EVT_STATE_CHANGE_NORMAL		0x00
-#define I2O_EVT_STATE_CHANGE_SUSPENDED		0x01
-#define I2O_EVT_STATE_CHANGE_RESTART		0x02
-#define I2O_EVT_STATE_CHANGE_NA_RECOVER		0x03
-#define I2O_EVT_STATE_CHANGE_NA_NO_RECOVER	0x04
-#define I2O_EVT_STATE_CHANGE_QUIESCE_REQUEST	0x05
-#define I2O_EVT_STATE_CHANGE_FAILED		0x10
-#define I2O_EVT_STATE_CHANGE_FAULTED		0x11
-
-#define I2O_EVT_GEN_WARNING_NORMAL		0x00
-#define I2O_EVT_GEN_WARNING_ERROR_THRESHOLD	0x01
-#define I2O_EVT_GEN_WARNING_MEDIA_FAULT		0x02
-
-#define I2O_EVT_CAPABILITY_OTHER		0x01
-#define I2O_EVT_CAPABILITY_CHANGED		0x02
-
-#define I2O_EVT_SENSOR_STATE_CHANGED		0x01
-
-#ifdef __KERNEL__   /* ioctl stuff only thing exported to users */
 
+/* How many OSMs can register themselves for device status updates? */
 #define I2O_MAX_MANAGERS	4
 
-/*
- *	I2O Interface Objects
- */
-
+#include <asm/semaphore.h> /* Needed for MUTEX init macros */
 #include <linux/config.h>
 #include <linux/notifier.h>
 #include <asm/atomic.h>
@@ -283,7 +35,6 @@
 /*
  * message structures
  */
-
 struct i2o_message
 {
 	u8	version_offset;
@@ -298,12 +49,11 @@
 
 /*
  *	Each I2O device entity has one or more of these. There is one
- *	per device. *FIXME* how to handle multiple types on one unit.
+ *	per device.
  */
- 
 struct i2o_device
 {
-	i2o_lct_entry *lct_data;/* Device LCT information */
+	i2o_lct_entry lct_data; /* Device LCT information */
 	u32 flags;		
 	int i2oversion;		/* I2O version supported. Actually there
 				 * should be high and low version */
@@ -329,15 +79,20 @@
 {
 	int irq;
 #ifdef CONFIG_MTRR
-	int mtrr_reg;
+	int mtrr_reg0;
+	int mtrr_reg1;
 #endif
 };
 
+/*
+ * Transport types supported by I2O stack
+ */
+#define I2O_TYPE_PCI		0x01		/* PCI I2O controller */	
+
 
 /*
- *	Each I2O controller has one of these objects
+ * Each I2O controller has one of these objects
  */
- 
 struct i2o_controller
 {
 	char name[16];
@@ -345,40 +100,43 @@
 	int type;
 	int enabled;
 
-#define I2O_TYPE_PCI		0x01		/* PCI I2O controller */	
-
 	struct notifier_block *event_notifer;	/* Events */
 	atomic_t users;
 	struct i2o_device *devices;		/* I2O device chain */
 	struct i2o_controller *next;		/* Controller chain */
-	volatile u32 *post_port;		/* Messaging ports */
-	volatile u32 *reply_port;
-	volatile u32 *irq_mask;			/* Interrupt port */
+	volatile u32 *post_port;		/* Inbout port */
+	volatile u32 *reply_port;		/* Outbound port */
+	volatile u32 *irq_mask;			/* Interrupt register */
+
+	/* Dynamic LCT related data */
+	struct semaphore lct_sem;
+	int lct_pid;
+	int lct_running;
 
 	i2o_status_block *status_block;		/* IOP status block */
-	i2o_lct *lct;
-	i2o_hrt *hrt;
+	i2o_lct *lct;				/* Logical Config Table */
+	i2o_lct *dlct;				/* Temp LCT */
+	i2o_hrt *hrt;				/* HW Resource Table */
 
 	u32 mem_offset;				/* MFA offset */
 	u32 mem_phys;				/* MFA physical */
 
-	u32 priv_mem;
-	u32 priv_mem_size;
-	u32 priv_io;
-	u32 priv_io_size;
-
 	struct proc_dir_entry* proc_entry;	/* /proc dir */
 
 	union
 	{					/* Bus information */
 		struct i2o_pci pci;
 	} bus;
+
 	/* Bus specific destructor */
 	void (*destructor)(struct i2o_controller *);		
+
 	/* Bus specific attach/detach */
 	int (*bind)(struct i2o_controller *, struct i2o_device *);	
+
 	/* Bus specific initiator */
 	int (*unbind)(struct i2o_controller *, struct i2o_device *);
+
 	/* Bus specific enable/disable */
 	void (*bus_enable)(struct i2o_controller *c);
 	void (*bus_disable)(struct i2o_controller *c);
@@ -387,12 +145,32 @@
 	int inbound_size;		/* Inbound queue size */
 };
 
+/*
+ * OSM resgistration block
+ *
+ * Each OSM creates at least one of these and registers it with the
+ * I2O core through i2o_register_handler.  An OSM may want to
+ * register more than one if it wants a fast path to a reply
+ * handler by having a separate initiator context for each 
+ * class function.
+ */
 struct i2o_handler
 {
+	/* Message reply handler */
 	void (*reply)(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);
-	char *name;
-	int context;		/* Low 8 bits of the transaction info */
-	u32 class;			/* I2O classes that this driver handles */
+
+	/* New device notification handler */
+	void (*new_dev_notify)(struct i2o_controller *, struct i2o_device *);
+
+	/* Device deltion handler */
+	void (*dev_del_notify)(struct i2o_controller *, struct i2o_device *);
+
+	/* Reboot notification handler */
+	void (*reboot_notify)(void);
+
+	char *name;		/* OSM name */
+	int context;	/* Low 8 bits of the transaction info */
+	u32 class;		/* I2O classes that this driver handles */
 	/* User data follows */
 };
 
@@ -416,10 +194,14 @@
 	void	(*run_queue)(struct i2o_controller *c);
 	int	(*delete)(struct i2o_controller *);
 };
-#endif
+#endif // MODULE
 
 /*
  * I2O System table entry
+ *
+ * The system table contains information about all the IOPs in the
+ * system.  It is sent to all IOPs so that they can create peer2peer
+ * connections between them.
  */
 struct i2o_sys_tbl_entry
 {
@@ -498,130 +280,55 @@
 	I2O_REPLY_WRITE32(c,m);
 }
 
-extern int i2o_install_controller(struct i2o_controller *);
-extern int i2o_delete_controller(struct i2o_controller *);
-extern void i2o_unlock_controller(struct i2o_controller *);
 extern struct i2o_controller *i2o_find_controller(int);
-extern int i2o_status_get(struct i2o_controller *);
+extern void i2o_unlock_controller(struct i2o_controller *);
+extern struct i2o_controller *i2o_controller_chain;
 extern int i2o_num_controllers;
+extern int i2o_status_get(struct i2o_controller *);
 
 extern int i2o_install_handler(struct i2o_handler *);
 extern int i2o_remove_handler(struct i2o_handler *);
 
-extern int i2o_claim_device(struct i2o_device *, struct i2o_handler *, u32);
-extern int i2o_release_device(struct i2o_device *, struct i2o_handler *, u32);
+extern int i2o_claim_device(struct i2o_device *, struct i2o_handler *);
+extern int i2o_release_device(struct i2o_device *, struct i2o_handler *);
+extern int i2o_device_notify_on(struct i2o_device *, struct i2o_handler *);
+extern int i2o_device_notify_off(struct i2o_device *, struct i2o_handler *);
 
 extern int i2o_post_this(struct i2o_controller *, u32 *, int);
 extern int i2o_post_wait(struct i2o_controller *, u32 *, int, int);
-extern int i2o_issue_params(int, struct i2o_controller *, int, void *,
-			    int, void *, int); 
 
 extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *, int);
 extern int i2o_set_scalar(struct i2o_controller *, int, int, int, void *, int);
-
 extern int i2o_query_table(int, struct i2o_controller *, int, int, int, void *,
 			   int, void *, int);
 extern int i2o_clear_table(struct i2o_controller *, int, int); 
 extern int i2o_row_add_table(struct i2o_controller *, int, int, int, void *,
 			     int);
+extern int i2o_row_delete_table(struct i2o_controller *, int, int, int, void *,
+				int);
+extern int i2o_issue_params(int, struct i2o_controller *, int, void *,
+			    int, void *, int); 
 
-extern int i2o_event_register(struct i2o_controller *, int, int, u32); 
-extern int i2o_event_ack(struct i2o_controller *, int, int, u32, void *, int);
+extern int i2o_event_register(struct i2o_controller *, u32, u32, u32, u32); 
+extern int i2o_event_ack(struct i2o_controller *, u32 *);
 
-extern void i2o_run_queue(struct i2o_controller *);
 extern void i2o_report_status(const char *, const char *, u32 *);
 extern void i2o_dump_message(u32 *);
-
 extern const char *i2o_get_class_name(int);
 
+extern int i2o_install_controller(struct i2o_controller *);
+extern int i2o_activate_controller(struct i2o_controller *);
+extern void i2o_run_queue(struct i2o_controller *);
+extern int i2o_delete_controller(struct i2o_controller *);
 
-/*
- *	I2O classes / subclasses
- */
-
-/*  Class ID and Code Assignments
- *  (LCT.ClassID.Version field)
- */
-#define    I2O_CLASS_VERSION_10                        0x00
-#define    I2O_CLASS_VERSION_11                        0x01
-
-/*  Class code names
- *  (from v1.5 Table 6-1 Class Code Assignments.)
- */
- 
-#define    I2O_CLASS_EXECUTIVE                         0x000
-#define    I2O_CLASS_DDM                               0x001
-#define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
-#define    I2O_CLASS_SEQUENTIAL_STORAGE                0x011
-#define    I2O_CLASS_LAN                               0x020
-#define    I2O_CLASS_WAN                               0x030
-#define    I2O_CLASS_FIBRE_CHANNEL_PORT                0x040
-#define    I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL          0x041
-#define    I2O_CLASS_SCSI_PERIPHERAL                   0x051
-#define    I2O_CLASS_ATE_PORT                          0x060
-#define    I2O_CLASS_ATE_PERIPHERAL                    0x061
-#define    I2O_CLASS_FLOPPY_CONTROLLER                 0x070
-#define    I2O_CLASS_FLOPPY_DEVICE                     0x071
-#define    I2O_CLASS_BUS_ADAPTER_PORT                  0x080
-#define    I2O_CLASS_PEER_TRANSPORT_AGENT              0x090
-#define    I2O_CLASS_PEER_TRANSPORT                    0x091
-
-/*  Rest of 0x092 - 0x09f reserved for peer-to-peer classes
- */
- 
-#define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
 
-/*  Subclasses
+/*
+ * I2O Function codes
  */
 
-#define    I2O_SUBCLASS_i960                           0x001
-#define    I2O_SUBCLASS_HDM                            0x020
-#define    I2O_SUBCLASS_ISM                            0x021
- 
-/* Operation functions */
-
-#define I2O_PARAMS_FIELD_GET	0x0001
-#define I2O_PARAMS_LIST_GET	0x0002
-#define I2O_PARAMS_MORE_GET	0x0003
-#define I2O_PARAMS_SIZE_GET	0x0004
-#define I2O_PARAMS_TABLE_GET	0x0005
-#define I2O_PARAMS_FIELD_SET	0x0006
-#define I2O_PARAMS_LIST_SET	0x0007
-#define I2O_PARAMS_ROW_ADD	0x0008
-#define I2O_PARAMS_ROW_DELETE	0x0009
-#define I2O_PARAMS_TABLE_CLEAR	0x000A
-
-/*
- *	I2O serial number conventions / formats
- *	(circa v1.5)
- */
-
-#define    I2O_SNFORMAT_UNKNOWN                        0
-#define    I2O_SNFORMAT_BINARY                         1
-#define    I2O_SNFORMAT_ASCII                          2
-#define    I2O_SNFORMAT_UNICODE                        3
-#define    I2O_SNFORMAT_LAN48_MAC                      4
-#define    I2O_SNFORMAT_WAN                            5
-
-/* Plus new in v2.0 (Yellowstone pdf doc)
- */
-
-#define    I2O_SNFORMAT_LAN64_MAC                      6
-#define    I2O_SNFORMAT_DDM                            7
-#define    I2O_SNFORMAT_IEEE_REG64                     8
-#define    I2O_SNFORMAT_IEEE_REG128                    9
-#define    I2O_SNFORMAT_UNKNOWN2                       0xff
-
-/* Transaction Reply Lists (TRL) Control Word structure */
-
-#define TRL_SINGLE_FIXED_LENGTH		0x00
-#define TRL_SINGLE_VARIABLE_LENGTH	0x40
-#define TRL_MULTIPLE_FIXED_LENGTH	0x80
-
 /*
- *	Messaging API values
- */
- 
+ * Executive Class
+ */ 
 #define	I2O_CMD_ADAPTER_ASSIGN		0xB3
 #define	I2O_CMD_ADAPTER_READ		0xB2
 #define	I2O_CMD_ADAPTER_RELEASE		0xB5
@@ -656,6 +363,9 @@
 #define	I2O_CMD_SYS_QUIESCE		0xC3
 #define	I2O_CMD_SYS_TAB_SET		0xA3
 
+/*
+ * Utility Class
+ */
 #define I2O_CMD_UTIL_NOP		0x00
 #define I2O_CMD_UTIL_ABORT		0x01
 #define I2O_CMD_UTIL_CLAIM		0x09
@@ -671,10 +381,16 @@
 #define I2O_CMD_UTIL_LOCK_RELEASE	0x19
 #define I2O_CMD_UTIL_REPLY_FAULT_NOTIFY	0x15
 
+/*
+ * SCSI Host Bus Adapter Class
+ */
 #define I2O_CMD_SCSI_EXEC		0x81
 #define I2O_CMD_SCSI_ABORT		0x83
 #define I2O_CMD_SCSI_BUSRESET		0x27
 
+/*
+ * Random Block Storage Class
+ */
 #define I2O_CMD_BLOCK_READ		0x30
 #define I2O_CMD_BLOCK_WRITE		0x31
 #define I2O_CMD_BLOCK_CFLUSH		0x37
@@ -688,24 +404,11 @@
 /*
  *	Init Outbound Q status 
  */
- 
 #define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS	0x01
 #define I2O_CMD_OUTBOUND_INIT_REJECTED		0x02
 #define I2O_CMD_OUTBOUND_INIT_FAILED		0x03
 #define I2O_CMD_OUTBOUND_INIT_COMPLETE		0x04
 
-/*
- *	I2O Get Status State values 
- */
-
-#define	ADAPTER_STATE_INITIALIZING		0x01
-#define	ADAPTER_STATE_RESET			0x02
-#define	ADAPTER_STATE_HOLD			0x04
-#define ADAPTER_STATE_READY			0x05
-#define	ADAPTER_STATE_OPERATIONAL		0x08
-#define	ADAPTER_STATE_FAILED			0x10
-#define	ADAPTER_STATE_FAULTED			0x11
-	
 /* I2O API function return values */
 
 #define I2O_RTN_NO_ERROR			0
@@ -796,8 +499,10 @@
 /* Message header defines for VersionOffset */
 #define I2OVER15	0x0001
 #define I2OVER20	0x0002
+
 /* Default is 1.5, FIXME: Need support for both 1.5 and 2.0 */
 #define I2OVERSION	I2OVER15
+
 #define SGL_OFFSET_0    I2OVERSION
 #define SGL_OFFSET_4    (0x0040 | I2OVERSION)
 #define SGL_OFFSET_5    (0x0050 | I2OVERSION)
@@ -810,6 +515,12 @@
 #define TRL_OFFSET_5    (0x0050 | I2OVERSION)
 #define TRL_OFFSET_6    (0x0060 | I2OVERSION)
 
+/* Transaction Reply Lists (TRL) Control Word structure */
+#define TRL_SINGLE_FIXED_LENGTH		0x00
+#define TRL_SINGLE_VARIABLE_LENGTH	0x40
+#define TRL_MULTIPLE_FIXED_LENGTH	0x80
+
+
  /* msg header defines for MsgFlags */
 #define MSG_STATIC	0x0100
 #define MSG_64BIT_CNTXT	0x0200
@@ -844,5 +555,4 @@
 #define I2O_POST_WAIT_TIMEOUT	-ETIMEDOUT
 
 #endif /* __KERNEL__ */
-
 #endif /* _I2O_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.99-pre5/linux/include/linux/ide.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/ide.h	Wed Apr 26 15:30:39 2000
@@ -300,13 +300,6 @@
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	void		*settings;	/* /proc/ide/ drive settings */
 	char		driver_req[10];	/* requests specific driver */
-#if 1
-	struct thresholds_s	*smart_thresholds;
-	struct values_s		*smart_values;
-#else
-	thresholds_t		smart_thresholds;
-	values_t		smart_values;
-#endif
 	int		last_lun;	/* last logical unit */
 	int		forced_lun;	/* if hdxlun was given at boot */
 } ide_drive_t;
@@ -385,7 +378,7 @@
 	ide_resetproc_t	*resetproc;	/* routine to reset controller after a disk reset */
 	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
 	unsigned int	*dmatable_cpu;	/* dma physical region descriptor table (cpu view) */
-	u32		dmatable_dma;	/* dma physical region descriptor table (dma view) */
+	dma_addr_t	dmatable_dma;	/* dma physical region descriptor table (dma view) */
 	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
 	int sg_nents;			/* Current number of entries in it */
 	int sg_dma_direction;		/* dma transfer direction */
@@ -538,6 +531,7 @@
 typedef int		(ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
 typedef void		(ide_release_proc)(struct inode *, struct file *, ide_drive_t *);
 typedef int		(ide_check_media_change_proc)(ide_drive_t *);
+typedef void		(ide_revalidate_proc)(ide_drive_t *);
 typedef void		(ide_pre_reset_proc)(ide_drive_t *);
 typedef unsigned long	(ide_capacity_proc)(ide_drive_t *);
 typedef ide_startstop_t	(ide_special_proc)(ide_drive_t *);
@@ -557,6 +551,7 @@
 	ide_open_proc			*open;
 	ide_release_proc		*release;
 	ide_check_media_change_proc	*media_change;
+	ide_revalidate_proc		*revalidate;
 	ide_pre_reset_proc		*pre_reset;
 	ide_capacity_proc		*capacity;
 	ide_special_proc		*special;
@@ -735,6 +730,7 @@
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
 
 void ide_delay_50ms (void);
+int system_bus_clock(void);
 
 int ide_driveid_update (ide_drive_t *drive);
 int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature);
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v2.3.99-pre5/linux/include/linux/interrupt.h	Fri Mar 10 16:40:49 2000
+++ linux/include/linux/interrupt.h	Wed Apr 26 15:29:07 2000
@@ -2,6 +2,7 @@
 #ifndef _LINUX_INTERRUPT_H
 #define _LINUX_INTERRUPT_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/cache.h>
@@ -154,7 +155,7 @@
 extern struct tasklet_head tasklet_vec[NR_CPUS];
 extern struct tasklet_head tasklet_hi_vec[NR_CPUS];
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define tasklet_trylock(t) (!test_and_set_bit(TASKLET_STATE_RUN, &(t)->state))
 #define tasklet_unlock_wait(t) while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { /* NOTHING */ }
 #define tasklet_unlock(t) clear_bit(TASKLET_STATE_RUN, &(t)->state)
@@ -213,7 +214,7 @@
 extern void tasklet_init(struct tasklet_struct *t,
 			 void (*func)(unsigned long), unsigned long data);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #define SMP_TIMER_NAME(name) name##__thr
 
@@ -224,12 +225,12 @@
 	tasklet_schedule(&(task)); \
 }
 
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
 
 #define SMP_TIMER_NAME(name) name
 #define SMP_TIMER_DEFINE(name, task)
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 
 /* Old BH definitions */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.3.99-pre5/linux/include/linux/kernel.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/kernel.h	Thu Apr 13 17:19:57 2000
@@ -83,6 +83,12 @@
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[3]
 
+#define HIPQUAD(addr) \
+	((unsigned char *)&addr)[3], \
+	((unsigned char *)&addr)[2], \
+	((unsigned char *)&addr)[1], \
+	((unsigned char *)&addr)[0]
+
 #endif /* __KERNEL__ */
 
 #define SI_LOAD_SHIFT	16
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/kernel_stat.h linux/include/linux/kernel_stat.h
--- v2.3.99-pre5/linux/include/linux/kernel_stat.h	Wed Aug 18 16:43:30 1999
+++ linux/include/linux/kernel_stat.h	Wed Apr 26 15:29:07 2000
@@ -1,6 +1,7 @@
 #ifndef _LINUX_KERNEL_STAT_H
 #define _LINUX_KERNEL_STAT_H
 
+#include <linux/config.h>
 #include <asm/irq.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
@@ -25,7 +26,9 @@
 	unsigned int dk_drive_wblk[DK_NDRIVE];
 	unsigned int pgpgin, pgpgout;
 	unsigned int pswpin, pswpout;
+#if !defined(CONFIG_ARCH_S390)
 	unsigned int irqs[NR_CPUS][NR_IRQS];
+#endif
 	unsigned int ipackets, opackets;
 	unsigned int ierrors, oerrors;
 	unsigned int collisions;
@@ -34,6 +37,7 @@
 
 extern struct kernel_stat kstat;
 
+#if !defined(CONFIG_ARCH_S390)
 /*
  * Number of interrupts per specific IRQ source, since bootup
  */
@@ -46,5 +50,6 @@
 
 	return sum;
 }
+#endif
 
 #endif /* _LINUX_KERNEL_STAT_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/major.h linux/include/linux/major.h
--- v2.3.99-pre5/linux/include/linux/major.h	Sun Feb 20 21:12:40 2000
+++ linux/include/linux/major.h	Wed Apr 26 12:13:16 2000
@@ -119,6 +119,8 @@
 
 #define AURORA_MAJOR 79
 
+#define JSFD_MAJOR	99
+
 #define PHONE_MAJOR	100
 
 #define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.99-pre5/linux/include/linux/mm.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/mm.h	Wed Apr 26 15:29:09 2000
@@ -15,6 +15,7 @@
 extern unsigned long num_physpages;
 extern void * high_memory;
 extern int page_cluster;
+extern struct list_head lru_cache;
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -89,6 +90,8 @@
 #define VM_SEQ_READ	0x00008000	/* App will access data sequentially */
 #define VM_RAND_READ	0x00010000	/* App will not benefit from clustered reads */
 
+#define VM_DONTCOPY	0x00020000      /* Do not copy this vma on fork */
+
 #define VM_STACK_FLAGS	0x00000177
 
 #define VM_READHINTMASK			(VM_SEQ_READ | VM_RAND_READ)
@@ -400,7 +403,7 @@
 extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
 
 extern void vmtruncate(struct inode * inode, loff_t offset);
-extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
@@ -443,7 +446,8 @@
 	return ret;
 }
 
-extern int do_munmap(unsigned long, size_t);
+extern int do_munmap(struct mm_struct *, unsigned long, size_t);
+
 extern unsigned long do_brk(unsigned long, unsigned long);
 
 struct zone_t;
@@ -529,7 +533,7 @@
 	return vma;
 }
 
-extern struct vm_area_struct *find_extend_vma(struct task_struct *tsk, unsigned long addr);
+extern struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr);
 
 #define buffer_under_min()	(atomic_read(&buffermem_pages) * 100 < \
 				buffer_mem.min_percent * num_physpages)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/mmzone.h linux/include/linux/mmzone.h
--- v2.3.99-pre5/linux/include/linux/mmzone.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/mmzone.h	Wed Apr 26 15:29:07 2000
@@ -31,7 +31,6 @@
 	char			low_on_memory;
 	char			zone_wake_kswapd;
 	unsigned long		pages_min, pages_low, pages_high;
-	struct list_head	lru_cache;
 
 	/*
 	 * free areas of different sizes
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/mount.h linux/include/linux/mount.h
--- v2.3.99-pre5/linux/include/linux/mount.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/mount.h	Mon Apr 24 13:40:52 2000
@@ -17,7 +17,7 @@
   char *mnt_devname;			/* Name of device e.g. /dev/dsk/hda1 */
   char *mnt_dirname;			/* Name of directory mounted on */
   struct super_block *mnt_sb;		/* pointer to superblock */
-  struct vfsmount *mnt_next;		/* pointer to next in linkedlist */
+	struct list_head mnt_list;
 };
 
 /* MOUNT_REWRITE: fill these */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.3.99-pre5/linux/include/linux/msdos_fs.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/msdos_fs.h	Wed Apr 12 09:47:29 2000
@@ -293,7 +293,6 @@
 extern unsigned char fat_esc2uni[];
 
 /* fatfs_syms.c */
-extern int init_fat_fs(void);
 extern void cleanup_fat_fs(void);
 
 /* nls.c */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/net.h linux/include/linux/net.h
--- v2.3.99-pre5/linux/include/linux/net.h	Tue Apr 11 15:09:24 2000
+++ linux/include/linux/net.h	Wed Apr 26 15:29:07 2000
@@ -104,8 +104,6 @@
 			 char *optval, int optlen);
   int	(*getsockopt)	(struct socket *sock, int level, int optname,
 			 char *optval, int *optlen);
-  int	(*fcntl)	(struct socket *sock, unsigned int cmd,
-			 unsigned long arg);	
   int   (*sendmsg)	(struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm);
   int   (*recvmsg)	(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
   int	(*mmap)		(struct file *file, struct socket *sock, struct vm_area_struct * vma);
@@ -194,8 +192,6 @@
 			 char *optval, int optlen), (sock, level, optname, optval, optlen)) \
 SOCKCALL_WRAP(name, getsockopt, (struct socket *sock, int level, int optname, \
 			 char *optval, int *optlen), (sock, level, optname, optval, optlen)) \
-SOCKCALL_WRAP(name, fcntl, (struct socket *sock, unsigned int cmd, \
-			 unsigned long arg), (sock, cmd, arg)) \
 SOCKCALL_WRAP(name, sendmsg, (struct socket *sock, struct msghdr *m, int len, struct scm_cookie *scm), \
 	      (sock, m, len, scm)) \
 SOCKCALL_WRAP(name, recvmsg, (struct socket *sock, struct msghdr *m, int len, int flags, struct scm_cookie *scm), \
@@ -203,25 +199,24 @@
 SOCKCALL_WRAP(name, mmap, (struct file *file, struct socket *sock, struct vm_area_struct *vma), \
 	      (file, sock, vma)) \
 	      \
-static struct proto_ops name##_ops = {	\
-	fam,				\
-					\
-	__lock_##name##_release,	\
-	__lock_##name##_bind,		\
-	__lock_##name##_connect,	\
-	__lock_##name##_socketpair,	\
-	__lock_##name##_accept,		\
-	__lock_##name##_getname,	\
-	__lock_##name##_poll,		\
-	__lock_##name##_ioctl,		\
-	__lock_##name##_listen,		\
-	__lock_##name##_shutdown,	\
-	__lock_##name##_setsockopt,	\
-	__lock_##name##_getsockopt,	\
-	__lock_##name##_fcntl,		\
-	__lock_##name##_sendmsg,	\
-	__lock_##name##_recvmsg,	\
-	__lock_##name##_mmap,		\
+static struct proto_ops name##_ops = {			\
+	family:		fam,				\
+							\
+	release:	__lock_##name##_release,	\
+	bind:		__lock_##name##_bind,		\
+	connect:	__lock_##name##_connect,	\
+	socketpair:	__lock_##name##_socketpair,	\
+	accept:		__lock_##name##_accept,		\
+	getname:	__lock_##name##_getname,	\
+	poll:		__lock_##name##_poll,		\
+	ioctl:		__lock_##name##_ioctl,		\
+	listen:		__lock_##name##_listen,		\
+	shutdown:	__lock_##name##_shutdown,	\
+	setsockopt:	__lock_##name##_setsockopt,	\
+	getsockopt:	__lock_##name##_getsockopt,	\
+	sendmsg:	__lock_##name##_sendmsg,	\
+	recvmsg:	__lock_##name##_recvmsg,	\
+	mmap:		__lock_##name##_mmap,		\
 };
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
--- v2.3.99-pre5/linux/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Wed Apr 26 15:32:31 2000
@@ -37,10 +37,10 @@
 		      struct iphdr *iph, size_t len,
 		      enum ip_conntrack_info ctinfo);
 
-	/* Called when a new connection for this protocol found; returns
-	 * TRUE if it's OK.  If so, packet() called next. */
-	int (*new)(struct ip_conntrack *conntrack,
-		   struct iphdr *iph, size_t len);
+	/* Called when a new connection for this protocol found;
+	 * returns timeout.  If so, packet() called next. */
+	unsigned long (*new)(struct ip_conntrack *conntrack,
+			     struct iphdr *iph, size_t len);
 
 	/* Module (if any) which this is connected to. */
 	struct module *me;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/netfilter_ipv4/ipt_state.h linux/include/linux/netfilter_ipv4/ipt_state.h
--- v2.3.99-pre5/linux/include/linux/netfilter_ipv4/ipt_state.h	Sun Mar 19 18:35:31 2000
+++ linux/include/linux/netfilter_ipv4/ipt_state.h	Fri Apr 14 09:37:20 2000
@@ -1,8 +1,7 @@
 #ifndef _IPT_STATE_H
 #define _IPT_STATE_H
 
-#define _IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)+1))
-#define IPT_STATE_BIT(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? _IPT_STATE_BIT((ctinfo)-IP_CT_IS_REPLY) : _IPT_STATE_BIT(ctinfo))
+#define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
 #define IPT_STATE_INVALID (1 << 0)
 
 struct ipt_state_info
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.3.99-pre5/linux/include/linux/nfs_fs.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/nfs_fs.h	Wed Apr 26 15:29:42 2000
@@ -45,6 +45,7 @@
  * The upper limit on timeouts for the exponential backoff algorithm.
  */
 #define NFS_MAX_RPC_TIMEOUT		(6*HZ)
+#define NFS_READ_DELAY			(2*HZ)
 #define NFS_WRITEBACK_DELAY		(5*HZ)
 #define NFS_WRITEBACK_LOCKDELAY		(60*HZ)
 #define NFS_COMMIT_DELAY		(5*HZ)
@@ -174,12 +175,9 @@
 /*
  * linux/fs/nfs/write.c
  */
-extern int  nfs_writepage(struct dentry *, struct page *);
-extern int  nfs_check_failed_request(struct inode *);
-extern struct nfs_page* nfs_find_request(struct inode *, struct page *);
-extern void nfs_release_request(struct nfs_page *req);
+extern int  nfs_writepage(struct file *file, struct dentry *, struct page *);
 extern int  nfs_flush_incompatible(struct file *file, struct page *page);
-extern int  nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int);
+extern int  nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
 /*
  * Try to write back everything synchronously (but check the
  * return value!)
@@ -193,6 +191,12 @@
 #endif
 
 static inline int
+nfs_have_read(struct inode *inode)
+{
+	return !list_empty(&inode->u.nfs_i.read);
+}
+
+static inline int
 nfs_have_writebacks(struct inode *inode)
 {
 	return !list_empty(&inode->u.nfs_i.writeback);
@@ -229,6 +233,8 @@
  * linux/fs/nfs/read.c
  */
 extern int  nfs_readpage(struct dentry *, struct page *);
+extern int  nfs_pagein_inode(struct inode *, unsigned long, unsigned int);
+extern int  nfs_pagein_timeout(struct inode *);
 
 /*
  * linux/fs/mount_clnt.c
@@ -275,7 +281,7 @@
 
 /* NFS root */
 
-extern int nfs_root_mount(struct super_block *sb);
+extern void * nfs_root_data(void);
 
 #define nfs_wait_event(clnt, wq, condition)				\
 ({									\
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v2.3.99-pre5/linux/include/linux/nfs_fs_i.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/nfs_fs_i.h	Tue Apr 25 17:28:56 2000
@@ -53,11 +53,13 @@
 	/*
 	 * This is the list of dirty unwritten pages.
 	 */
+	struct list_head	read;
 	struct list_head	dirty;
 	struct list_head	commit;
 	struct list_head	writeback;
 
-	unsigned int		ndirty,
+	unsigned int		nread,
+				ndirty,
 				ncommit,
 				npages;
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/nfs_fs_sb.h linux/include/linux/nfs_fs_sb.h
--- v2.3.99-pre5/linux/include/linux/nfs_fs_sb.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/nfs_fs_sb.h	Tue Apr 25 17:28:56 2000
@@ -9,7 +9,9 @@
 	struct nfs_rpc_ops *	rpc_ops;	/* NFS protocol vector */
 	int			flags;		/* various flags */
 	unsigned int		rsize;		/* read size */
+	unsigned int		rpages;		/* read size (in pages) */
 	unsigned int		wsize;		/* write size */
+	unsigned int		wpages;		/* write size (in pages) */
 	unsigned int		dtsize;		/* readdir size */
 	unsigned int		bsize;		/* server block size */
 	unsigned int		acregmin;	/* attr cache timeouts */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/nfs_page.h linux/include/linux/nfs_page.h
--- v2.3.99-pre5/linux/include/linux/nfs_page.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/nfs_page.h	Wed Apr 26 15:29:45 2000
@@ -0,0 +1,102 @@
+/*
+ * linux/include/linux/nfs_page.h
+ *
+ * Copyright (C) 2000 Trond Myklebust
+ *
+ * NFS page cache wrapper.
+ */
+
+#ifndef _LINUX_NFS_PAGE_H
+#define _LINUX_NFS_PAGE_H
+
+
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/nfs_xdr.h>
+
+/*
+ * Valid flags for a dirty buffer
+ */
+#define PG_BUSY			0x0001
+
+struct nfs_page {
+	struct list_head	wb_hash,	/* Inode */
+				wb_list,	/* Defines state of page: */
+				*wb_list_head;	/*      read/write/commit */
+	struct file		*wb_file;
+	struct dentry		*wb_dentry;
+	struct rpc_cred		*wb_cred;
+	struct page		*wb_page;	/* page to read in/write out */
+	wait_queue_head_t	wb_wait;	/* wait queue */
+	unsigned long		wb_timeout;	/* when to read/write/commit */
+	unsigned int		wb_offset,	/* Offset of read/write */
+				wb_bytes,	/* Length of request */
+				wb_count,	/* reference count */
+				wb_flags;
+	struct nfs_writeverf	wb_verf;	/* Commit cookie */
+};
+
+#define NFS_WBACK_BUSY(req)	((req)->wb_flags & PG_BUSY)
+
+extern	struct nfs_page *nfs_create_request(struct dentry *dentry,
+					    struct page *page,
+					    unsigned int offset,
+					    unsigned int count);
+extern	void nfs_release_request(struct nfs_page *req);
+
+
+extern	void nfs_list_add_request(struct nfs_page *req,
+				  struct list_head *head);
+extern	void nfs_list_remove_request(struct nfs_page *req);
+
+extern	int nfs_scan_list_timeout(struct list_head *head,
+				  struct list_head *dst,
+				  struct inode *inode);
+extern	int nfs_scan_list(struct list_head *src, struct list_head *dst,
+			  struct file *file, unsigned long idx_start,
+			  unsigned int npages);
+extern	int nfs_coalesce_requests(struct list_head *src, struct list_head *dst,
+				  unsigned int maxpages);
+
+extern	spinlock_t nfs_wreq_lock;
+
+/*
+ * Lock the page of an asynchronous request
+ */
+static __inline__ int
+nfs_lock_request(struct nfs_page *req)
+{
+	if (NFS_WBACK_BUSY(req))
+		return 0;
+	req->wb_count++;
+	req->wb_flags |= PG_BUSY;
+	return 1;
+}
+
+static __inline__ void
+nfs_unlock_request(struct nfs_page *req)
+{
+	if (!NFS_WBACK_BUSY(req)) {
+		printk(KERN_ERR "NFS: Invalid unlock attempted\n");
+		return;
+	}
+	req->wb_flags &= ~PG_BUSY;
+	wake_up(&req->wb_wait);
+	nfs_release_request(req);
+}
+
+static __inline__ struct nfs_page *
+nfs_list_entry(struct list_head *head)
+{
+	return list_entry(head, struct nfs_page, wb_list);
+}
+
+static __inline__ struct nfs_page *
+nfs_inode_wb_entry(struct list_head *head)
+{
+	return list_entry(head, struct nfs_page, wb_hash);
+}
+
+#endif /* _LINUX_NFS_PAGE_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.99-pre5/linux/include/linux/parport.h	Wed Feb 16 17:03:52 2000
+++ linux/include/linux/parport.h	Wed Apr 26 15:31:16 2000
@@ -380,8 +380,26 @@
 
 extern void parport_release(struct pardevice *dev);
 
-/* parport_yield relinquishes the port if it would be helpful to other
-   drivers.  The return value is the same as for parport_claim.  */
+/**
+ * parport_yield - relinquish a parallel port temporarily
+ * @dev: a device on the parallel port
+ *
+ * This function relinquishes the port if it would be helpful to other
+ * drivers to do so.  Afterwards it tries to reclaim the port using
+ * parport_claim(), and the return value is the same as for
+ * parport_claim().  If it fails, the port is left unclaimed and it is
+ * the driver's responsibility to reclaim the port.
+ *
+ * The parport_yield() and parport_yield_blocking() functions are for
+ * marking points in the driver at which other drivers may claim the
+ * port and use their devices.  Yielding the port is similar to
+ * releasing it and reclaiming it, but is more efficient because no
+ * action is taken if there are no other devices needing the port.  In
+ * fact, nothing is done even if there are other devices waiting but
+ * the current device is still within its "timeslice".  The default
+ * timeslice is half a second, but it can be adjusted via the /proc
+ * interface.
+ **/
 extern __inline__ int parport_yield(struct pardevice *dev)
 {
 	unsigned long int timeslip = (jiffies - dev->time);
@@ -391,8 +409,15 @@
 	return parport_claim(dev);
 }
 
-/* parport_yield_blocking is the same but uses parport_claim_or_block
-   instead of parport_claim.  */
+/**
+ * parport_yield_blocking - relinquish a parallel port temporarily
+ * @dev: a device on the parallel port
+ *
+ * This function relinquishes the port if it would be helpful to other
+ * drivers to do so.  Afterwards it tries to reclaim the port using
+ * parport_claim_or_block(), and the return value is the same as for
+ * parport_claim_or_block().
+ **/
 extern __inline__ int parport_yield_blocking(struct pardevice *dev)
 {
 	unsigned long int timeslip = (jiffies - dev->time);
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.3.99-pre5/linux/include/linux/pci_ids.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/pci_ids.h	Thu Apr 13 22:54:26 2000
@@ -807,6 +807,8 @@
 #define PCI_VENDOR_ID_ARTOP		0x1191
 #define PCI_DEVICE_ID_ARTOP_ATP8400	0x0004
 #define PCI_DEVICE_ID_ARTOP_ATP850UF	0x0005
+#define PCI_DEVICE_ID_ARTOP_ATP860	0x0006
+#define PCI_DEVICE_ID_ARTOP_ATP860R	0x0007
 
 #define PCI_VENDOR_ID_ZEITNET		0x1193
 #define PCI_DEVICE_ID_ZEITNET_1221	0x0001
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/personality.h linux/include/linux/personality.h
--- v2.3.99-pre5/linux/include/linux/personality.h	Tue Mar 14 19:10:40 2000
+++ linux/include/linux/personality.h	Fri Apr 21 13:36:40 2000
@@ -3,7 +3,7 @@
 
 #include <linux/linkage.h>
 #include <linux/ptrace.h>
-
+#include <asm/current.h>
 
 /* Flags for bug emulation. These occupy the top three bytes. */
 #define STICKY_TIMEOUTS		0x4000000
@@ -22,6 +22,7 @@
 #define PER_WYSEV386		(0x0004 | STICKY_TIMEOUTS)
 #define PER_ISCR4		(0x0005 | STICKY_TIMEOUTS)
 #define PER_BSD			(0x0006)
+#define PER_SUNOS		(PER_BSD | STICKY_TIMEOUTS)
 #define PER_XENIX		(0x0007 | STICKY_TIMEOUTS)
 #define PER_LINUX32		(0x0008)
 #define PER_IRIX32              (0x0009 | STICKY_TIMEOUTS) /* IRIX5 32-bit     */
@@ -51,11 +52,17 @@
 
 extern struct exec_domain default_exec_domain;
 
-extern struct exec_domain *lookup_exec_domain(unsigned long personality);
 extern int register_exec_domain(struct exec_domain *it);
 extern int unregister_exec_domain(struct exec_domain *it);
 #define put_exec_domain(it) \
 	if (it && it->module) __MOD_DEC_USE_COUNT(it->module);
+#define get_exec_domain(it) \
+	if (it && it->module) __MOD_INC_USE_COUNT(it->module);
+extern void __set_personality(unsigned long personality);
+#define set_personality(pers) do {	\
+	if (current->personality != pers) \
+		__set_personality(pers); \
+} while (0)
 asmlinkage long sys_personality(unsigned long personality);
 
 #endif /* _PERSONALITY_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/raid/md_u.h linux/include/linux/raid/md_u.h
--- v2.3.99-pre5/linux/include/linux/raid/md_u.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/raid/md_u.h	Wed Apr 12 09:18:19 2000
@@ -17,12 +17,6 @@
 
 /* ioctls */
 
-/* compat */
-#define REGISTER_DEV 		_IO (MD_MAJOR, 1)
-#define START_MD     		_IO (MD_MAJOR, 2)
-#define STOP_MD      		_IO (MD_MAJOR, 3)
-
-
 /* status */
 #define RAID_VERSION		_IOR (MD_MAJOR, 0x10, mdu_version_t)
 #define GET_ARRAY_INFO		_IOR (MD_MAJOR, 0x11, mdu_array_info_t)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/rtc.h linux/include/linux/rtc.h
--- v2.3.99-pre5/linux/include/linux/rtc.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/rtc.h	Fri Apr 21 15:21:18 2000
@@ -28,6 +28,17 @@
 };
 
 /*
+ * This data structure is inspired by the EFI (v0.92) wakeup
+ * alarm API.
+ */
+struct rtc_wkalrm {
+	unsigned char enabled;	/* 0 = alarm disable, 1 = alarm disabled */
+	unsigned char pending;  /* 0 = alarm pending, 1 = alarm not pending */
+	struct rtc_time time;	/* time the alarm is set to */
+};
+
+
+/*
  * ioctl calls that are permitted to the /dev/rtc interface, if 
  * CONFIG_RTC/CONFIG_EFI_RTC was enabled.
  */
@@ -47,5 +58,8 @@
 #define RTC_IRQP_SET	_IOW('p', 0x0c, unsigned long)	 /* Set IRQ rate    */
 #define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
 #define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
+
+#define RTC_WKALM_SET	_IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
+#define RTC_WKALM_RD	_IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
 
 #endif /* _LINUX_RTC_H_ */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.99-pre5/linux/include/linux/sched.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/sched.h	Wed Apr 26 15:29:08 2000
@@ -5,6 +5,7 @@
 
 extern unsigned long event;
 
+#include <linux/config.h>
 #include <linux/binfmts.h>
 #include <linux/personality.h>
 #include <linux/threads.h>
@@ -23,6 +24,7 @@
 #include <linux/sem.h>
 #include <linux/signal.h>
 #include <linux/securebits.h>
+#include <linux/fs_struct.h>
 
 /*
  * cloning flags:
@@ -84,7 +86,7 @@
 
 #define __set_task_state(tsk, state_value)		\
 	do { (tsk)->state = (state_value); } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define set_task_state(tsk, state_value)		\
 	set_mb((tsk)->state, (state_value))
 #else
@@ -94,7 +96,7 @@
 
 #define __set_current_state(state_value)			\
 	do { current->state = (state_value); } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define set_current_state(state_value)		\
 	set_mb(current->state, (state_value))
 #else
@@ -181,19 +183,6 @@
 	{ NULL, } \
 }
 
-struct fs_struct {
-	atomic_t count;
-	int umask;
-	struct dentry * root, * pwd;
-	struct vfsmount * rootmnt, * pwdmnt;
-};
-
-#define INIT_FS { \
-	ATOMIC_INIT(1), \
-	0022, \
-	NULL, NULL, NULL, NULL \
-}
-
 /* Maximum number of active map areas.. This is a random (large) number */
 #define MAX_MAP_COUNT	(65536)
 
@@ -214,7 +203,7 @@
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack;
 	unsigned long arg_start, arg_end, env_start, env_end;
-	unsigned long rss, total_vm, locked_vm;
+	unsigned long min_flt, maj_flt, rss, total_vm, locked_vm;
 	unsigned long def_flags;
 	unsigned long cpu_vm_mask;
 	unsigned long swap_cnt;	/* number of pages to swap on next pass */
@@ -236,7 +225,7 @@
 		0, 0, 0, 0,				\
 		0, 0, 0, 				\
 		0, 0, 0, 0,				\
-		0, 0, 0,				\
+		0, 0, 0, 0, 0,				\
 		0, 0, 0, 0, NULL }
 
 struct signal_struct {
@@ -321,6 +310,7 @@
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
 	unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
 	int swappable:1;
+	int hog:1;
 /* process credentials */
 	uid_t uid,euid,suid,fsuid;
 	gid_t gid,egid,sgid,fsgid;
@@ -709,7 +699,6 @@
 extern void exit_thread(void);
 
 extern void exit_mm(struct task_struct *);
-extern void exit_fs(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.3.99-pre5/linux/include/linux/skbuff.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/skbuff.h	Wed Apr 26 15:30:00 2000
@@ -99,6 +99,12 @@
 
 	struct  dst_entry *dst;
 
+	/* 
+	 * This is the control buffer. It is free to use for every
+	 * layer. Please put your private variables there. If you
+	 * want to keep them across layers you have to do a skb_clone()
+	 * first. This is owned by whoever has the skb queued ATM.
+	 */ 
 	char		cb[48];	 
 
 	unsigned int 	len;			/* Length of actual data			*/
@@ -130,13 +136,6 @@
         unsigned int nf_debug;
 #endif
 #endif /*CONFIG_NETFILTER*/
-#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
-	__u32		shapelatency;		/* Latency on frame */
-	__u32		shapeclock;		/* Time it should go out */
-	__u32		shapelen;		/* Frame length in clocks */
-	__u32		shapestamp;		/* Stamp for shaper    */
-	__u16		shapepend;		/* Pending */
-#endif
 
 #if defined(CONFIG_HIPPI)
 	union{
@@ -211,7 +210,7 @@
  *	skb_queue_empty - check if a queue is empty
  *	@list: queue head
  *
- *	Returns true if the queue is empty, false otherwise
+ *	Returns true if the queue is empty, false otherwise.
  */
  
 extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
@@ -240,7 +239,7 @@
  
 /**
  *	kfree_skb - free an sk_buff
- *	@skb: The buffer to free
+ *	@skb: buffer to free
  *
  *	Drop a reference to the buffer and free it if the usage count has
  *	hit zero.
@@ -261,9 +260,9 @@
 
 /**
  *	skb_cloned - is the buffer a clone
- *	@skb: Buffer to check
+ *	@skb: buffer to check
  *
- *	Returns true if the buffer was generated with skb_clone and is
+ *	Returns true if the buffer was generated with skb_clone() and is
  *	one of multiple shared copies of the buffer. Cloned buffers are
  *	shared data so must not be written to under normal circumstances.
  */
@@ -328,9 +327,9 @@
  *	copy of the data, drops a reference count on the old copy and returns
  *	the new copy with the reference count at 1. If the buffer is not a clone
  *	the original buffer is returned. When called with a spinlock held or
- *	from interrupt state pri must be GFP_ATOMIC
+ *	from interrupt state @pri must be %GFP_ATOMIC
  *
- *	NULL is returned on a memory allocation failure.
+ *	%NULL is returned on a memory allocation failure.
  */
  
 extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
@@ -347,12 +346,12 @@
  *	skb_peek
  *	@list_: list to peek at
  *
- *	Peek an sk_buff. Unlike most other operations you _MUST_
+ *	Peek an &sk_buff. Unlike most other operations you _MUST_
  *	be careful with this one. A peek leaves the buffer on the
  *	list and someone else may run off with it. You must hold
  *	the appropriate locks or have a private queue to do this.
  *
- *	Returns NULL for an empty list or a pointer to the head element.
+ *	Returns %NULL for an empty list or a pointer to the head element.
  *	The reference count is not incremented and the reference is therefore
  *	volatile. Use with caution.
  */
@@ -369,12 +368,12 @@
  *	skb_peek_tail
  *	@list_: list to peek at
  *
- *	Peek an sk_buff. Unlike most other operations you _MUST_
+ *	Peek an &sk_buff. Unlike most other operations you _MUST_
  *	be careful with this one. A peek leaves the buffer on the
  *	list and someone else may run off with it. You must hold
  *	the appropriate locks or have a private queue to do this.
  *
- *	Returns NULL for an empty list or a pointer to the tail element.
+ *	Returns %NULL for an empty list or a pointer to the tail element.
  *	The reference count is not incremented and the reference is therefore
  *	volatile. Use with caution.
  */
@@ -391,7 +390,7 @@
  *	skb_queue_len	- get queue length
  *	@list_: list to measure
  *
- *	Return the length of an sk_buff queue. 
+ *	Return the length of an &sk_buff queue. 
  */
  
 extern __inline__ __u32 skb_queue_len(struct sk_buff_head *list_)
@@ -446,7 +445,7 @@
  *	@newsk: buffer to queue
  *
  *	Queue a buffer at the start of the list. This function takes the
- *	list lock and can be used safely with other locking sk_buff functions
+ *	list lock and can be used safely with other locking &sk_buff functions
  *	safely.
  *
  *	A buffer cannot be placed on two lists at the same time.
@@ -493,7 +492,7 @@
  *	@newsk: buffer to queue
  *
  *	Queue a buffer at the tail of the list. This function takes the
- *	list lock and can be used safely with other locking sk_buff functions
+ *	list lock and can be used safely with other locking &sk_buff functions
  *	safely.
  *
  *	A buffer cannot be placed on two lists at the same time.
@@ -514,7 +513,7 @@
  *
  *	Remove the head of the list. This function does not take any locks
  *	so must be used with appropriate locks held only. The head item is
- *	returned or NULL if the list is empty.
+ *	returned or %NULL if the list is empty.
  */
 
 extern __inline__ struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
@@ -543,7 +542,7 @@
  *
  *	Remove the head of the list. The list lock is taken so the function
  *	may be used safely with other locking list functions. The head item is
- *	returned or NULL if the list is empty.
+ *	returned or %NULL if the list is empty.
  */
 
 extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list)
@@ -675,7 +674,7 @@
  *
  *	Remove the tail of the list. This function does not take any locks
  *	so must be used with appropriate locks held only. The tail item is
- *	returned or NULL if the list is empty.
+ *	returned or %NULL if the list is empty.
  */
 
 extern __inline__ struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
@@ -692,7 +691,7 @@
  *
  *	Remove the head of the list. The list lock is taken so the function
  *	may be used safely with other locking list functions. The tail item is
- *	returned or NULL if the list is empty.
+ *	returned or %NULL if the list is empty.
  */
 
 extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
@@ -725,7 +724,7 @@
  *
  *	This function extends the used data area of the buffer. If this would
  *	exceed the total buffer size the kernel will panic. A pointer to the
- *	first byte of the extra data is returned
+ *	first byte of the extra data is returned.
  */
  
 extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
@@ -752,8 +751,8 @@
  *	@len: amount of data to add
  *
  *	This function extends the used data area of the buffer at the buffer
- *	start. If this would  exceed the total buffer headroom the kernel will
- *	 panic. A pointer to the first byte of the extra data is returned
+ *	start. If this would exceed the total buffer headroom the kernel will
+ *	panic. A pointer to the first byte of the extra data is returned.
  */
 
 extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
@@ -777,10 +776,10 @@
  *	@skb: buffer to use 
  *	@len: amount of data to remove
  *
- *	This function  removes data from the start of a buffer, returning
+ *	This function removes data from the start of a buffer, returning
  *	the memory to the headroom. A pointer to the next data in the buffer
  *	is returned. Once the data has been pulled future pushes will overwrite
- *	the old data
+ *	the old data.
  */
 
 extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
@@ -794,7 +793,7 @@
  *	skb_headroom - bytes at buffer head
  *	@skb: buffer to check
  *
- *	Return the number of bytes of free space at the head of an sk_buff
+ *	Return the number of bytes of free space at the head of an &sk_buff.
  */
  
 extern __inline__ int skb_headroom(const struct sk_buff *skb)
@@ -819,7 +818,7 @@
  *	@skb: buffer to alter
  *	@len: bytes to move
  *
- *	Increase the headroom of an empty sk_buff by reducing the tail
+ *	Increase the headroom of an empty &sk_buff by reducing the tail
  *	room. This is only allowed for an empty buffer.
  */
 
@@ -856,8 +855,8 @@
  *	skb_orphan - orphan a buffer
  *	@skb: buffer to orphan
  *
- *	If a buffer currently has an owner then we call the owners
- *	destructor function and make the skb unowned. The buffer continues
+ *	If a buffer currently has an owner then we call the owner's
+ *	destructor function and make the @skb unowned. The buffer continues
  *	to exist but is no longer charged to its former owner.
  */
 
@@ -874,7 +873,7 @@
  *	skb_purge - empty a list
  *	@list: list to empty
  *
- *	Delete all buffers on an sk_buff list. Each buffer is removed from
+ *	Delete all buffers on an &sk_buff list. Each buffer is removed from
  *	the list and one reference dropped. This function takes the list
  *	lock and is atomic with respect to other list locking functions.
  */
@@ -891,7 +890,7 @@
  *	__skb_purge - empty a list
  *	@list: list to empty
  *
- *	Delete all buffers on an sk_buff list. Each buffer is removed from
+ *	Delete all buffers on an &sk_buff list. Each buffer is removed from
  *	the list and one reference dropped. This function does not take the
  *	list lock and the caller must hold the relevant locks to use it.
  */
@@ -908,12 +907,12 @@
  *	dev_alloc_skb - allocate an skbuff for sending
  *	@length: length to allocate
  *
- *	Allocate a new sk_buff and assign it a usage count of one. The
+ *	Allocate a new &sk_buff and assign it a usage count of one. The
  *	buffer has unspecified headroom built in. Users should allocate
  *	the headroom they think they need without accounting for the
  *	built in space. The built in space is used for optimisations.
  *
- *	NULL is returned in there is no free memory. Although this function
+ *	%NULL is returned in there is no free memory. Although this function
  *	allocates memory it can be called from an interrupt.
  */
  
@@ -934,7 +933,7 @@
  *
  *	If the buffer passed lacks sufficient headroom or is a clone then
  *	it is copied and the additional headroom made available. If there
- *	is no free memory NULL is returned. The new buffer is returned if
+ *	is no free memory %NULL is returned. The new buffer is returned if
  *	a copy was made (and the old one dropped a reference). The existing
  *	buffer is returned otherwise.
  *
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.3.99-pre5/linux/include/linux/smp.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/smp.h	Wed Apr 26 15:29:07 2000
@@ -6,7 +6,9 @@
  *		Alan Cox. <alan@redhat.com>
  */
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 
 #include <asm/smp.h>
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/smp_lock.h linux/include/linux/smp_lock.h
--- v2.3.99-pre5/linux/include/linux/smp_lock.h	Mon Mar 27 08:08:32 2000
+++ linux/include/linux/smp_lock.h	Wed Apr 26 15:29:09 2000
@@ -1,7 +1,9 @@
 #ifndef __LINUX_SMPLOCK_H
 #define __LINUX_SMPLOCK_H
 
-#ifndef __SMP__
+#include <linux/config.h>
+
+#ifndef CONFIG_SMP
 
 #define lock_kernel()				do { } while(0)
 #define unlock_kernel()				do { } while(0)
@@ -13,6 +15,6 @@
 
 #include <asm/smplock.h>
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 #endif
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/spinlock.h linux/include/linux/spinlock.h
--- v2.3.99-pre5/linux/include/linux/spinlock.h	Sun Feb 20 21:12:40 2000
+++ linux/include/linux/spinlock.h	Wed Apr 26 15:29:06 2000
@@ -1,6 +1,8 @@
 #ifndef __LINUX_SPINLOCK_H
 #define __LINUX_SPINLOCK_H
 
+#include <linux/config.h>
+
 /*
  * These are the generic versions of the spinlocks and read-write
  * locks..
@@ -29,7 +31,7 @@
 #define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
 #define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #include <asm/spinlock.h>
 
 #else /* !SMP */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/string.h linux/include/linux/string.h
--- v2.3.99-pre5/linux/include/linux/string.h	Fri Jan 21 18:19:17 2000
+++ linux/include/linux/string.h	Wed Apr 26 15:29:07 2000
@@ -31,6 +31,7 @@
 extern void * memmove(void *,const void *,__kernel_size_t);
 extern void * memscan(void *,int,__kernel_size_t);
 extern int memcmp(const void *,const void *,__kernel_size_t);
+extern void * memchr(const void *,int,__kernel_size_t);
 
 /*
  * Include machine specific inline routines
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.99-pre5/linux/include/linux/swap.h	Tue Apr 11 15:09:25 2000
+++ linux/include/linux/swap.h	Wed Apr 26 15:29:07 2000
@@ -51,6 +51,7 @@
 	kdev_t swap_device;
 	spinlock_t sdev_lock;
 	struct dentry * swap_file;
+	struct vfsmount *swap_vfsmnt;
 	unsigned short * swap_map;
 	unsigned int lowest_bit;
 	unsigned int highest_bit;
@@ -86,6 +87,7 @@
 
 /* linux/mm/vmscan.c */
 extern int try_to_free_pages(unsigned int gfp_mask, zone_t *zone);
+extern int swap_out(unsigned int gfp_mask, int priority);
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *, int);
@@ -166,7 +168,7 @@
 #define	lru_cache_add(page)			\
 do {						\
 	spin_lock(&pagemap_lru_lock);		\
-	list_add(&(page)->lru, &page->zone->lru_cache);	\
+	list_add(&(page)->lru, &lru_cache);	\
 	nr_lru_pages++;				\
 	spin_unlock(&pagemap_lru_lock);		\
 } while (0)
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.99-pre5/linux/include/linux/sysctl.h	Fri Mar 10 16:40:50 2000
+++ linux/include/linux/sysctl.h	Wed Apr 26 15:06:25 2000
@@ -119,7 +119,7 @@
 enum
 {
 	VM_SWAPCTL=1,		/* struct: Set vm swapping control */
-	VM_SWAPOUT=2,		/* int: Background pageout interval */
+	VM_SWAPOUT=2,		/* int: Linear or sqrt() swapout for hogs */
 	VM_FREEPG=3,		/* struct: Set free page thresholds */
 	VM_BDFLUSH=4,		/* struct: Control buffer cache flushing */
 	VM_OVERCOMMIT_MEMORY=5,	/* Turn off the virtual memory safety limit */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/threads.h linux/include/linux/threads.h
--- v2.3.99-pre5/linux/include/linux/threads.h	Wed Aug 18 16:43:28 1999
+++ linux/include/linux/threads.h	Wed Apr 26 15:29:06 2000
@@ -1,12 +1,14 @@
 #ifndef _LINUX_THREADS_H
 #define _LINUX_THREADS_H
 
+#include <linux/config.h>
+
 /*
  * The default limit for the nr of threads is now in
  * /proc/sys/kernel/max-threads.
  */
  
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define NR_CPUS	32		/* Max processors that can be running in SMP */
 #else
 #define NR_CPUS 1
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/timer.h linux/include/linux/timer.h
--- v2.3.99-pre5/linux/include/linux/timer.h	Sat Feb 26 22:32:07 2000
+++ linux/include/linux/timer.h	Wed Apr 26 15:29:07 2000
@@ -1,6 +1,8 @@
 #ifndef _LINUX_TIMER_H
 #define _LINUX_TIMER_H
 
+#include <linux/config.h>
+
 /*
  * Old-style timers. Please don't use for any new code.
  *
@@ -69,7 +71,7 @@
 {
 	timer->next = NULL;
 	timer->prev = NULL;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	timer->running = 0;
 #endif
 }
@@ -79,17 +81,17 @@
 	return timer->prev != NULL;
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define timer_exit(t) do { (t)->running = 0; mb(); } while (0)
 #define timer_set_running(t) do { (t)->running = 1; mb(); } while (0)
 #define timer_is_running(t) ((t)->running != 0)
 #define timer_synchronize(t) while (timer_is_running(t)) barrier()
 extern int del_timer_sync(struct timer_list * timer);
 #else
-#define timer_exit(t) do { } while (0)
-#define timer_set_running(t) do { } while (0)
+#define timer_exit(t) (void)(t)
+#define timer_set_running(t) (void)(t)
 #define timer_is_running(t) (0)
-#define timer_synchronize(t) barrier()
+#define timer_synchronize(t) do { (void)(t); barrier(); } while(0)
 #define del_timer_sync(t) del_timer(t)
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.3.99-pre5/linux/include/linux/usb.h	Wed Apr 12 10:02:34 2000
+++ linux/include/linux/usb.h	Mon Apr 24 13:39:37 2000
@@ -160,7 +160,7 @@
 
 #define __set_current_state(state_value)                        \
 	do { current->state = state_value; } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define set_current_state(state_value)          \
 	set_mb(current->state, state_value)
 #else
@@ -618,7 +618,7 @@
  *  - current Data0/1 state (1 bit)
  *  - direction (1 bit)
  *  - speed (1 bit)
- *  - max packet size (2 bits: 8, 16, 32 or 64)
+ *  - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.]
  *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
  *
  * That's 18 bits. Really. Nothing more. And the USB people have
@@ -628,7 +628,7 @@
  * Let's not fall in that trap. We'll just encode it as a simple
  * unsigned int. The encoding is:
  *
- *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64)
+ *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64) [Historical; now gone.]
  *  - direction:	bit 7		(0 = Host-to-Device [Out], 1 = Device-to-Host [In])
  *  - device:		bits 8-14
  *  - endpoint:		bits 15-18
@@ -646,11 +646,6 @@
 #define PIPE_INTERRUPT			1
 #define PIPE_CONTROL			2
 #define PIPE_BULK			3
-
-#define USB_ISOCHRONOUS		0
-#define USB_INTERRUPT		1
-#define USB_CONTROL		2
-#define USB_BULK		3
 
 #define usb_maxpacket(dev, pipe, out)	(out \
 				? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.3.99-pre5/linux/include/linux/videodev.h	Fri Mar 10 16:40:50 2000
+++ linux/include/linux/videodev.h	Wed Apr 12 09:47:29 2000
@@ -373,6 +373,7 @@
 #define VID_HARDWARE_ZR36120	25	/* Zoran ZR36120/ZR36125 */
 #define VID_HARDWARE_ZR36067	26	/* Zoran ZR36067/36060 */
 #define VID_HARDWARE_OV511	27	
+#define VID_HARDWARE_ZR356700	28	/* Zoran 36700 series */
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/wanpipe.h linux/include/linux/wanpipe.h
--- v2.3.99-pre5/linux/include/linux/wanpipe.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/wanpipe.h	Mon Apr 24 13:39:37 2000
@@ -35,7 +35,9 @@
 #ifndef	_WANPIPE_H
 #define	_WANPIPE_H
 
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 #include <asm/spinlock.h>       /* Support for SMP Locking */
 #endif
 
@@ -251,7 +253,7 @@
 	unsigned short force_enable_irq;
 	char TracingEnabled;		/* flag for enabling trace */
 	global_stats_t statistics;	/* global statistics */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	spinlock_t lock;                /* Support for SMP Locking */
 #endif
 	void* mbox;			/* -> mailbox */
diff -u --recursive --new-file v2.3.99-pre5/linux/include/linux/x25.h linux/include/linux/x25.h
--- v2.3.99-pre5/linux/include/linux/x25.h	Mon Oct  5 10:04:35 1998
+++ linux/include/linux/x25.h	Fri Apr 14 09:37:20 2000
@@ -1,5 +1,9 @@
 /*
  * These are the public elements of the Linux kernel X.25 implementation.
+ *
+ * 	History
+ *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities 
+ *					  negotiation.
  */
 
 #ifndef	X25_KERNEL_H
@@ -49,11 +53,26 @@
 
 /*
  *	DTE/DCE subscription options.
+ *
+ *      As this is missing lots of options, user should expect major
+ *	changes of this structure in 2.5.x which might break compatibilty.
+ *      The somewhat ugly dimension 200-sizeof() is needed to maintain
+ *	backward compatibility.
  */
 struct x25_subscrip_struct {
-	char device[200];
+	char device[200-sizeof(unsigned long)];
+	unsigned long	global_facil_mask;	/* 0 to disable negotiation */
 	unsigned int	extended;
 };
+
+/* values for above global_facil_mask */
+
+#define	X25_MASK_REVERSE	0x01	
+#define	X25_MASK_THROUGHPUT	0x02
+#define	X25_MASK_PACKET_SIZE	0x04
+#define	X25_MASK_WINDOW_SIZE	0x08
+
+
 
 /*
  *	Routing table control structure.
diff -u --recursive --new-file v2.3.99-pre5/linux/include/net/af_unix.h linux/include/net/af_unix.h
--- v2.3.99-pre5/linux/include/net/af_unix.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/af_unix.h	Mon Apr 24 13:43:04 2000
@@ -1,7 +1,6 @@
 #ifndef __LINUX_NET_AFUNIX_H
 #define __LINUX_NET_AFUNIX_H
 extern void unix_proto_init(struct net_proto *pro);
-extern struct proto_ops unix_proto_ops;
 extern void unix_inflight(struct file *fp);
 extern void unix_notinflight(struct file *fp);
 typedef struct sock unix_socket;
diff -u --recursive --new-file v2.3.99-pre5/linux/include/net/dn.h linux/include/net/dn.h
--- v2.3.99-pre5/linux/include/net/dn.h	Tue Jan 11 22:31:45 2000
+++ linux/include/net/dn.h	Wed Apr 26 15:29:08 2000
@@ -180,7 +180,7 @@
 
 extern struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr);
 extern struct sock *dn_find_by_skb(struct sk_buff *skb);
-#define DN_ASCBUF_LEN 7
+#define DN_ASCBUF_LEN 9
 extern char *dn_addr2asc(dn_address, char *);
 extern int dn_destroy_timer(struct sock *sk);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/net/sock.h linux/include/net/sock.h
--- v2.3.99-pre5/linux/include/net/sock.h	Tue Apr 11 15:09:25 2000
+++ linux/include/net/sock.h	Wed Apr 26 15:30:16 2000
@@ -356,7 +356,10 @@
 	 */
 	rwlock_t		syn_wait_lock;
 	struct tcp_listen_opt	*listen_opt;
-	struct open_request	*accept_queue; /* Established children */
+
+	/* FIFO of established children */
+	struct open_request	*accept_queue;
+	struct open_request	*accept_queue_tail;
 
 	int write_pending;	/* A write to socket waits to start. */
 
@@ -597,7 +600,6 @@
 
 
 	/* This part is used for the timeout functions. */
-	spinlock_t		timer_lock;	/* Required until timer in core is repaired */
 	struct timer_list	timer;		/* This is the sock cleanup timer. */
 	struct timeval		stamp;
 
@@ -818,7 +820,7 @@
 						struct msghdr *, int,
 						struct scm_cookie *);
 extern int                      sock_no_recvmsg(struct socket *,
-						struct msghdr *, int,
+						struct msghdr *, int, int,
 						struct scm_cookie *);
 extern int			sock_no_mmap(struct file *file,
 					     struct socket *sock,
diff -u --recursive --new-file v2.3.99-pre5/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.3.99-pre5/linux/include/net/tcp.h	Tue Apr 11 15:09:25 2000
+++ linux/include/net/tcp.h	Wed Apr 26 15:30:41 2000
@@ -1383,8 +1383,13 @@
 	req->sk = child;
 	tcp_acceptq_added(sk);
 
-	req->dl_next = tp->accept_queue;
-	tp->accept_queue = req;
+	if (!tp->accept_queue_tail) {
+		tp->accept_queue = req;
+	} else {
+		tp->accept_queue_tail->dl_next = req;
+	}
+	tp->accept_queue_tail = req;
+	req->dl_next = NULL;
 }
 
 struct tcp_listen_opt
@@ -1486,10 +1491,8 @@
 		return;
 	};
 
-	spin_lock_bh(&sk->timer_lock);
-	if (timer->prev != NULL && del_timer(timer))
+	if (timer_pending(timer) && del_timer(timer))
 		__sock_put(sk);
-	spin_unlock_bh(&sk->timer_lock);
 }
 
 /* This function does not return reliable answer. Use it only as advice.
diff -u --recursive --new-file v2.3.99-pre5/linux/include/net/x25.h linux/include/net/x25.h
--- v2.3.99-pre5/linux/include/net/x25.h	Tue Nov 23 22:42:21 1999
+++ linux/include/net/x25.h	Fri Apr 14 09:37:20 2000
@@ -1,7 +1,10 @@
 /*
  *	Declarations of X.25 Packet Layer type objects.
  *
- *	Jonathan Naylor		17/11/96
+ * 	History
+ *	nov/17/96	Jonathan Naylor	  Initial version.		
+ *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities 
+ *					  negotiation.
  */
 
 #ifndef _X25_H
@@ -113,6 +116,7 @@
 	struct sk_buff_head	queue;
 	unsigned long		t20;
 	struct timer_list	t20timer;
+	unsigned long		global_facil_mask;
 };
 
 typedef struct {
@@ -132,6 +136,7 @@
 	struct x25_causediag	causediag;
 	struct x25_facilities	facilities;
 	struct x25_calluserdata	calluserdata;
+	unsigned long 		vc_facil_mask;	/* inc_call facilities mask */
 } x25_cb;
 
 /* af_x25.c */
@@ -159,8 +164,8 @@
 extern void x25_terminate_link(struct x25_neigh *);
 
 /* x25_facilities.c */
-extern int  x25_parse_facilities(struct sk_buff *, struct x25_facilities *);
-extern int  x25_create_facilities(unsigned char *, struct x25_facilities *);
+extern int  x25_parse_facilities(struct sk_buff *, struct x25_facilities *, unsigned long *);
+extern int  x25_create_facilities(unsigned char *, struct x25_facilities *, unsigned long);
 extern int  x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *);
 extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
 
diff -u --recursive --new-file v2.3.99-pre5/linux/include/video/fbcon.h linux/include/video/fbcon.h
--- v2.3.99-pre5/linux/include/video/fbcon.h	Tue Dec  7 09:32:51 1999
+++ linux/include/video/fbcon.h	Wed Apr 12 09:12:35 2000
@@ -192,6 +192,43 @@
 #define SCROLL_YNOPARTIAL	__SCROLL_YNOPARTIAL
 
 
+#if defined(__sparc__)
+
+/* We map all of our framebuffers such that big-endian accesses
+ * are what we want, so the following is sufficient.
+ */
+
+#define fb_readb sbus_readb
+#define fb_readw sbus_readw
+#define fb_readl sbus_readl
+#define fb_writeb sbus_writeb
+#define fb_writew sbus_writew
+#define fb_writel sbus_writel
+#define fb_memset sbus_memset_io
+
+#elif defined(__i386__) || defined(__alpha__)
+
+#define fb_readb __raw_readb
+#define fb_readw __raw_readw
+#define fb_readl __raw_readl
+#define fb_writeb __raw_writeb
+#define fb_writew __raw_writew
+#define fb_writel __raw_writel
+#define fb_memset memset_io
+
+#else
+
+#define fb_readb(addr) (*(volatile u8 *) (addr))
+#define fb_readw(addr) (*(volatile u16 *) (addr))
+#define fb_readl(addr) (*(volatile u32 *) (addr))
+#define fb_writeb(b,addr) (*(volatile u8 *) (addr) = (b))
+#define fb_writew(b,addr) (*(volatile u16 *) (addr) = (b))
+#define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b))
+#define fb_memset memset
+
+#endif
+
+
 extern void fbcon_redraw_bmove(struct display *, int, int, int, int, int, int);
 
 
@@ -489,17 +526,68 @@
 
 static __inline__ void *fb_memclear_small(void *s, size_t count)
 {
-    return(memset(s, 0, count));
+    char *xs = (char *) s;
+
+    while (count--)
+	fb_writeb(0, xs++);
+
+    return s;
 }
 
 static __inline__ void *fb_memclear(void *s, size_t count)
 {
-    return(memset(s, 0, count));
+    unsigned long xs = (unsigned long) s;
+
+    if (count < 8)
+	goto rest;
+
+    if (xs & 1) {
+	fb_writeb(0, xs++);
+	count--;
+    }
+    if (xs & 2) {
+	fb_writew(0, xs);
+	xs += 2;
+	count -= 2;
+    }
+    while (count > 3) {
+	fb_writel(0, xs);
+	xs += 4;
+	count -= 4;
+    }
+rest:
+    while (count--)
+	fb_writeb(0, xs++);
+
+    return s;
 }
 
 static __inline__ void *fb_memset255(void *s, size_t count)
 {
-    return(memset(s, 255, count));
+    unsigned long xs = (unsigned long) s;
+
+    if (count < 8)
+	goto rest;
+
+    if (xs & 1) {
+	fb_writeb(0xff, xs++);
+	count--;
+    }
+    if (xs & 2) {
+	fb_writew(0xffff, xs);
+	xs += 2;
+	count -= 2;
+    }
+    while (count > 3) {
+	fb_writel(0xffffffff, xs);
+	xs += 4;
+	count -= 4;
+    }
+rest:
+    while (count--)
+	fb_writeb(0xff, xs++);
+
+    return s;
 }
 
 #if defined(__i386__)
@@ -553,7 +641,7 @@
     return dst;
 }
 
-#else /* !i386 */
+#else /* !__i386__ */
 
     /*
      *  Anyone who'd like to write asm functions for other CPUs?
@@ -562,53 +650,130 @@
 
 static __inline__ void *fb_memmove(void *d, const void *s, size_t count)
 {
-    return(memmove(d, s, count));
-}
+    unsigned long dst, src;
 
-static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
-{
-    memmove(dst, src, size);
-}
+    if (d < s) {
+	dst = (unsigned long) d;
+	src = (unsigned long) s;
 
-#endif /* !i386 */
+	if ((count < 8) || ((dst ^ src) & 3))
+	    goto restup;
 
-#endif
+	if (dst & 1) {
+	    fb_writeb(fb_readb(src++), dst++);
+	    count--;
+	}
+	if (dst & 2) {
+	    fb_writew(fb_readw(src), dst);
+	    src += 2;
+	    dst += 2;
+	    count -= 2;
+	}
+	while (count > 3) {
+	    fb_writel(fb_readl(src), dst);
+	    src += 4;
+	    dst += 4;
+	    count -= 4;
+	}
+
+    restup:
+	while (count--)
+	    fb_writeb(fb_readb(src++), dst++);
+    } else {
+	dst = (unsigned long) d + count - 1;
+	src = (unsigned long) s + count - 1;
 
+	if ((count < 8) || ((dst ^ src) & 3))
+	    goto restdown;
 
-#if defined(__sparc__)
+	if (dst & 1) {
+	    fb_writeb(fb_readb(src--), dst--);
+	    count--;
+	}
+	if (dst & 2) {
+	    fb_writew(fb_readw(src), dst);
+	    src -= 2;
+	    dst -= 2;
+	    count -= 2;
+	}
+	while (count > 3) {
+	    fb_writel(fb_readl(src), dst);
+	    src -= 4;
+	    dst -= 4;
+	    count -= 4;
+	}
+
+    restdown:
+	while (count--)
+	    fb_writeb(fb_readb(src--), dst--);
+    }
 
-/* We map all of our framebuffers such that big-endian accesses
- * are what we want, so the following is sufficient.
- */
+    return d;
+}
 
-#define fb_readb sbus_readb
-#define fb_readw sbus_readw
-#define fb_readl sbus_readl
-#define fb_writeb sbus_writeb
-#define fb_writew sbus_writew
-#define fb_writel sbus_writel
-#define fb_memset sbus_memset_io
+static __inline__ void fast_memmove(char *d, const char *s, size_t count)
+{
+    unsigned long dst, src;
 
-#elif defined(__i386__) || defined(__alpha__)
+    if (d < s) {
+	dst = (unsigned long) d;
+	src = (unsigned long) s;
 
-#define fb_readb __raw_readb
-#define fb_readw __raw_readw
-#define fb_readl __raw_readl
-#define fb_writeb __raw_writeb
-#define fb_writew __raw_writew
-#define fb_writel __raw_writel
-#define fb_memset memset_io
+	if ((count < 8) || ((dst ^ src) & 3))
+	    goto restup;
 
-#else
+	if (dst & 1) {
+	    fb_writeb(fb_readb(src++), dst++);
+	    count--;
+	}
+	if (dst & 2) {
+	    fb_writew(fb_readw(src), dst);
+	    src += 2;
+	    dst += 2;
+	    count -= 2;
+	}
+	while (count > 3) {
+	    fb_writel(fb_readl(src), dst);
+	    src += 4;
+	    dst += 4;
+	    count -= 4;
+	}
+
+    restup:
+	while (count--)
+	    fb_writeb(fb_readb(src++), dst++);
+    } else {
+	dst = (unsigned long) d + count - 1;
+	src = (unsigned long) s + count - 1;
 
-#define fb_readb(addr) (*(volatile u8 *) (addr))
-#define fb_readw(addr) (*(volatile u16 *) (addr))
-#define fb_readl(addr) (*(volatile u32 *) (addr))
-#define fb_writeb(b,addr) (*(volatile u8 *) (addr) = (b))
-#define fb_writew(b,addr) (*(volatile u16 *) (addr) = (b))
-#define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b))
-#define fb_memset memset
+	if ((count < 8) || ((dst ^ src) & 3))
+	    goto restdown;
 
-#endif
+	if (dst & 1) {
+	    fb_writeb(fb_readb(src--), dst--);
+	    count--;
+	}
+	if (dst & 2) {
+	    fb_writew(fb_readw(src), dst);
+	    src -= 2;
+	    dst -= 2;
+	    count -= 2;
+	}
+	while (count > 3) {
+	    fb_writel(fb_readl(src), dst);
+	    src -= 4;
+	    dst -= 4;
+	    count -= 4;
+	}
+
+    restdown:
+	while (count--)
+	    fb_writeb(fb_readb(src--), dst--);
+    }
+}
+
+#endif /* !__i386__ */
+
+#endif /* !__mc68000__ */
 
 #endif /* _VIDEO_FBCON_H */
diff -u --recursive --new-file v2.3.99-pre5/linux/init/main.c linux/init/main.c
--- v2.3.99-pre5/linux/init/main.c	Tue Apr 11 15:09:25 2000
+++ linux/init/main.c	Wed Apr 26 12:13:17 2000
@@ -47,6 +47,10 @@
 #  include <asm/mtrr.h>
 #endif
 
+#ifdef CONFIG_3215_CONSOLE
+extern int con3215_activate(void);
+#endif
+
 #ifdef CONFIG_MAC
 extern void nubus_init(void);
 #endif
@@ -69,7 +73,7 @@
  * To avoid associated bogus bug reports, we flatly refuse to compile
  * with a gcc that is known to be too old from the very beginning.
  */
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6)
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
 #error sorry, your GCC is too old. It builds incorrect kernels.
 #endif
 
@@ -246,6 +250,27 @@
 	{ "pf",		0x2f00 },
 	{ "apblock", APBLOCK_MAJOR << 8},
 	{ "ddv", DDV_MAJOR << 8},
+	{ "jsfd",    JSFD_MAJOR << 8},
+#ifdef CONFIG_MDISK
+        { "mnda", (MDISK_MAJOR << MINORBITS)},
+        { "mndb", (MDISK_MAJOR << MINORBITS) + 1},
+        { "mndc", (MDISK_MAJOR << MINORBITS) + 2},
+        { "mndd", (MDISK_MAJOR << MINORBITS) + 3},
+        { "mnde", (MDISK_MAJOR << MINORBITS) + 4},
+        { "mndf", (MDISK_MAJOR << MINORBITS) + 5},
+        { "mndg", (MDISK_MAJOR << MINORBITS) + 6},
+        { "mndh", (MDISK_MAJOR << MINORBITS) + 7},
+#endif
+#ifdef CONFIG_DASD
+	{ "dasda", (DASD_MAJOR << MINORBITS) },
+	{ "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) },
+	{ "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) },
+	{ "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) },
+	{ "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) },
+	{ "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) },
+	{ "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) },
+	{ "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) },
+#endif
 	{ NULL, 0 }
 };
 
@@ -395,7 +420,7 @@
  */
 static void __init parse_options(char *line)
 {
-	char *next;
+	char *next,*quote;
 	int args, envs;
 
 	if (!*line)
@@ -404,8 +429,20 @@
 	envs = 1;	/* TERM is set to 'linux' by default */
 	next = line;
 	while ((line = next) != NULL) {
-		if ((next = strchr(line,' ')) != NULL)
-			*next++ = 0;
+                quote = strchr(line,'"');
+                next = strchr(line, ' ');
+                while (next != NULL && quote != NULL && quote < next) {
+                        /* we found a left quote before the next blank
+                         * now we have to find the matching right quote
+                         */
+                        next = strchr(quote+1, '"');
+                        if (next != NULL) {
+                                quote = strchr(next+1, '"');
+                                next = strchr(next+1, ' ');
+                        }
+                }
+                if (next != NULL)
+                        *next++ = 0;
 		if (!strncmp(line,"init=",5)) {
 			line += 5;
 			execute_command = line;
@@ -431,6 +468,7 @@
 		} else {
 			if (args >= MAX_INIT_ARGS)
 				break;
+                        if(*line)
 			argv_init[++args] = line;
 		}
 	}
@@ -442,7 +480,7 @@
 extern void setup_arch(char **);
 extern void cpu_idle(void);
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 
 #ifdef CONFIG_X86_IO_APIC
 static void __init smp_init(void)
@@ -520,6 +558,9 @@
 #endif
 	mem_init();
 	kmem_cache_sizes_init();
+#ifdef CONFIG_3215_CONSOLE
+        con3215_activate();
+#endif
 #ifdef CONFIG_PROC_FS
 	proc_root_init();
 #endif
@@ -527,14 +568,14 @@
 
 	fork_init(mempages);
 	filescache_init();
-	dcache_init();
+	dcache_init(mempages);
 	vma_init();
 	buffer_init(mempages);
 	page_cache_init(mempages);
 	kiobuf_setup();
 	signals_init();
 	bdev_init();
-	inode_init();
+	inode_init(mempages);
 	file_table_init();
 #if defined(CONFIG_SYSVIPC)
 	ipc_init();
diff -u --recursive --new-file v2.3.99-pre5/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.99-pre5/linux/ipc/shm.c	Tue Apr 11 15:09:25 2000
+++ linux/ipc/shm.c	Wed Apr 26 09:12:56 2000
@@ -370,7 +370,7 @@
 
 static int shm_statfs(struct super_block *sb, struct statfs *buf)
 {
-	buf->f_type = 0;
+	buf->f_type = SHM_FS_MAGIC;
 	buf->f_bsize = PAGE_SIZE;
 	buf->f_blocks = shm_ctlall;
 	buf->f_bavail = buf->f_bfree = shm_ctlall - shm_tot;
@@ -1202,7 +1202,7 @@
 	sprintf (name, SHM_FMT, shmid);
 
 	lock_kernel();
-	dentry = lookup_one(name, dget(lock_parent(shm_sb->s_root)));
+	dentry = lookup_one(name, lock_parent(shm_sb->s_root));
 	unlock_dir(shm_sb->s_root);
 	err = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
@@ -1256,7 +1256,7 @@
 	sprintf (name, SHM_FMT, id);
 	lock_kernel();
 	dir = lock_parent(shm_sb->s_root);
-	dentry = lookup_one(name, dget(dir));
+	dentry = lookup_one(name, dir);
 	error = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		/*
@@ -1320,16 +1320,17 @@
  */
 asmlinkage long sys_shmdt (char *shmaddr)
 {
+	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *shmd, *shmdnext;
 
-	down(&current->mm->mmap_sem);
-	for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
+	down(&mm->mmap_sem);
+	for (shmd = mm->mmap; shmd; shmd = shmdnext) {
 		shmdnext = shmd->vm_next;
 		if (shmd->vm_ops == &shm_vm_ops
 		    && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr)
-			do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
+			do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start);
 	}
-	up(&current->mm->mmap_sem);
+	up(&mm->mmap_sem);
 	return 0;
 }
 
@@ -1715,12 +1716,13 @@
 	d_instantiate(filp->f_dentry, inp);
 
 	/*
-	 * Copy over /dev/zero dev/ino for benefit of procfs. Use
+	 * Copy over dev/ino for benefit of procfs. Use
 	 * ino to indicate seperate mappings.
 	 */
-	filp->f_dentry->d_inode->i_dev = fzero->f_dentry->d_inode->i_dev;
+	filp->f_dentry->d_inode->i_dev = shm_sb->s_dev;
 	filp->f_dentry->d_inode->i_ino = (unsigned long)shp;
-	fput(fzero);	/* release /dev/zero file */
+	if (fzero)
+		fput(fzero);	/* release /dev/zero file */
 	return(filp);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/exec_domain.c linux/kernel/exec_domain.c
--- v2.3.99-pre5/linux/kernel/exec_domain.c	Tue Mar 14 19:10:40 2000
+++ linux/kernel/exec_domain.c	Fri Apr 21 13:36:40 2000
@@ -32,9 +32,7 @@
    * personality set incorrectly.  Check to see whether SVr4 is available,
    * and use it, otherwise give the user a SEGV.
    */
-	put_exec_domain(current->exec_domain);
-	current->personality = PER_SVR4;
-	current->exec_domain = lookup_exec_domain(current->personality);
+	set_personality(PER_SVR4);
 
 	if (current->exec_domain && current->exec_domain->handler
 	&& current->exec_domain->handler != no_lcall7) {
@@ -45,7 +43,7 @@
 	send_sig(SIGSEGV, current, 1);
 }
 
-struct exec_domain *lookup_exec_domain(unsigned long personality)
+static struct exec_domain *lookup_exec_domain(unsigned long personality)
 {
 	unsigned long pers = personality & PER_MASK;
 	struct exec_domain *it;
@@ -104,28 +102,37 @@
 	return -EINVAL;
 }
 
-asmlinkage long sys_personality(unsigned long personality)
+void __set_personality(unsigned long personality)
 {
 	struct exec_domain *it;
-	unsigned long old_personality;
-	int ret;
-
-	if (personality == 0xffffffff)
-		return current->personality;
 
-	ret = -EINVAL;
-	lock_kernel();
 	it = lookup_exec_domain(personality);
-	if (!it)
-		goto out;
+	if (it) {
+		if (atomic_read(&current->fs->count) != 1) {
+			struct fs_struct *new = copy_fs_struct(current->fs);
+			if (!new)
+				return;
+			put_fs_struct(xchg(&current->fs,new));
+		}
+		/*
+		 * At that point we are guaranteed to be the sole owner of
+		 * current->fs.
+		 */
+		current->personality = personality;
+		current->exec_domain = it;
+		set_fs_altroot();
+		put_exec_domain(current->exec_domain);
+	}
+}
 
-	old_personality = current->personality;
-	put_exec_domain(current->exec_domain);
-	current->personality = personality;
-	current->exec_domain = it;
-	ret = old_personality;
-out:
-	unlock_kernel();
+asmlinkage long sys_personality(unsigned long personality)
+{
+	int ret = current->personality;
+	if (personality != 0xffffffff) {
+		set_personality(personality);
+		if (current->personality != personality)
+			ret = -EINVAL;
+	}
 	return ret;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.99-pre5/linux/kernel/exit.c	Tue Apr 11 15:09:25 2000
+++ linux/kernel/exit.c	Mon Apr 24 15:47:25 2000
@@ -25,7 +25,7 @@
 static void release(struct task_struct * p)
 {
 	if (p != current) {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		int has_cpu;
 
 		/*
@@ -207,6 +207,25 @@
 {
 	__exit_files(tsk);
 }
+static inline void __put_fs_struct(struct fs_struct *fs)
+{
+	if (atomic_dec_and_test(&fs->count)) {
+		dput(fs->root);
+		mntput(fs->rootmnt);
+		dput(fs->pwd);
+		mntput(fs->pwdmnt);
+		if (fs->altroot) {
+			dput(fs->altroot);
+			mntput(fs->altrootmnt);
+		}
+		kfree(fs);
+	}
+}
+
+void put_fs_struct(struct fs_struct *fs)
+{
+	__put_fs_struct(fs);
+}
 
 static inline void __exit_fs(struct task_struct *tsk)
 {
@@ -214,13 +233,7 @@
 
 	if (fs) {
 		tsk->fs = NULL;
-		if (atomic_dec_and_test(&fs->count)) {
-			dput(fs->root);
-			mntput(fs->rootmnt);
-			dput(fs->pwd);
-			mntput(fs->pwdmnt);
-			kfree(fs);
-		}
+		__put_fs_struct(fs);
 	}
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.99-pre5/linux/kernel/fork.c	Tue Apr 11 15:09:25 2000
+++ linux/kernel/fork.c	Fri Apr 21 16:08:45 2000
@@ -11,6 +11,7 @@
  * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
  */
 
+#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
 #include <linux/unistd.h>
@@ -98,7 +99,7 @@
  * the common case (not freeing anything) without having
  * any locking.
  */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
   #define uid_hash_free(up)	(!atomic_read(&(up)->count))
 #else
   #define uid_hash_free(up)	(1)
@@ -242,6 +243,8 @@
 		struct file *file;
 
 		retval = -ENOMEM;
+		if(mpnt->vm_flags & VM_DONTCOPY)
+			continue;
 		tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 		if (!tmp)
 			goto fail_nomem;
@@ -419,21 +422,41 @@
 	return retval;
 }
 
+static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old)
+{
+	struct fs_struct *fs = kmalloc(sizeof(*old), GFP_KERNEL);
+	if (fs) {
+		atomic_set(&fs->count, 1);
+		fs->umask = old->umask;
+		fs->rootmnt = mntget(old->rootmnt);
+		fs->root = dget(old->root);
+		fs->pwdmnt = mntget(old->pwdmnt);
+		fs->pwd = dget(old->pwd);
+		if (old->altroot) {
+			fs->altrootmnt = mntget(old->altrootmnt);
+			fs->altroot = dget(old->altroot);
+		} else {
+			fs->altrootmnt = NULL;
+			fs->altroot = NULL;
+		}	
+	}
+	return fs;
+}
+
+struct fs_struct *copy_fs_struct(struct fs_struct *old)
+{
+	return __copy_fs_struct(old);
+}
+
 static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
 {
 	if (clone_flags & CLONE_FS) {
 		atomic_inc(&current->fs->count);
 		return 0;
 	}
-	tsk->fs = kmalloc(sizeof(*tsk->fs), GFP_KERNEL);
+	tsk->fs = __copy_fs_struct(current->fs);
 	if (!tsk->fs)
 		return -1;
-	atomic_set(&tsk->fs->count, 1);
-	tsk->fs->umask = current->fs->umask;
-	tsk->fs->root = dget(current->fs->root);
-	tsk->fs->pwd = dget(current->fs->pwd);
-	tsk->fs->rootmnt = mntget(current->fs->rootmnt);
-	tsk->fs->pwdmnt = mntget(current->fs->pwdmnt);
 	return 0;
 }
 
@@ -673,7 +696,7 @@
 	p->tty_old_pgrp = 0;
 	p->times.tms_utime = p->times.tms_stime = 0;
 	p->times.tms_cutime = p->times.tms_cstime = 0;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	{
 		int i;
 		p->has_cpu = 0;
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.3.99-pre5/linux/kernel/kmod.c	Tue Apr 11 15:09:25 2000
+++ linux/kernel/kmod.c	Fri Apr 21 13:36:40 2000
@@ -52,17 +52,18 @@
 	lock_kernel();
 
 	our_fs = current->fs;
-	dput(our_fs->root);
-	dput(our_fs->pwd);
-	mntput(our_fs->rootmnt);
-	mntput(our_fs->pwdmnt);
-
 	init_fs = init_task.fs;
 	our_fs->umask = init_fs->umask;
-	our_fs->root = dget(init_fs->root);
-	our_fs->pwd = dget(init_fs->pwd);
-	our_fs->rootmnt = mntget(init_fs->rootmnt);
-	our_fs->pwdmnt = mntget(init_fs->pwdmnt);
+	set_fs_root(our_fs, init_fs->rootmnt, init_fs->root);
+	set_fs_pwd(our_fs, init_fs->pwdmnt, init_fs->pwd);
+	if (our_fs->altroot) {
+		struct vfsmount *mnt = our_fs->altrootmnt;
+		struct dentry *dentry = our_fs->altroot;
+		our_fs->altrootmnt = NULL;
+		our_fs->altroot = NULL;
+		dput(dentry);
+		mntput(mnt);
+	}
 
 	unlock_kernel();
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.99-pre5/linux/kernel/ksyms.c	Tue Apr 11 15:09:25 2000
+++ linux/kernel/ksyms.c	Wed Apr 26 09:11:31 2000
@@ -52,6 +52,11 @@
 #include <linux/kmod.h>
 #endif
 
+#ifdef CONFIG_BLK_DEV_LVM_MODULE
+extern void (*lvm_hd_name_ptr) ( char*, int);
+EXPORT_SYMBOL(lvm_hd_name_ptr);
+#endif
+
 extern int console_loglevel;
 extern void set_device_ro(kdev_t dev,int flag);
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
@@ -179,6 +184,7 @@
 EXPORT_SYMBOL(set_blocksize);
 EXPORT_SYMBOL(getblk);
 EXPORT_SYMBOL(bdget);
+EXPORT_SYMBOL(bdput);
 EXPORT_SYMBOL(bread);
 EXPORT_SYMBOL(breada);
 EXPORT_SYMBOL(__brelse);
@@ -189,6 +195,7 @@
 EXPORT_SYMBOL(block_write_full_page);
 EXPORT_SYMBOL(block_read_full_page);
 EXPORT_SYMBOL(block_prepare_write);
+EXPORT_SYMBOL(block_sync_page);
 EXPORT_SYMBOL(cont_prepare_write);
 EXPORT_SYMBOL(generic_commit_write);
 EXPORT_SYMBOL(generic_block_bmap);
@@ -235,15 +242,17 @@
 EXPORT_SYMBOL(page_readlink);
 EXPORT_SYMBOL(page_follow_link);
 EXPORT_SYMBOL(page_symlink_inode_operations);
+EXPORT_SYMBOL(block_fsync);
 EXPORT_SYMBOL(block_symlink);
 EXPORT_SYMBOL(vfs_readdir);
 
-/* for stackable file systems (lofs, wrapfs, etc.) */
-EXPORT_SYMBOL(add_to_page_cache);
+/* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
+EXPORT_SYMBOL(default_llseek);
+EXPORT_SYMBOL(dentry_open);
 EXPORT_SYMBOL(filemap_nopage);
 EXPORT_SYMBOL(filemap_swapout);
 EXPORT_SYMBOL(filemap_sync);
-EXPORT_SYMBOL(remove_inode_page);
+EXPORT_SYMBOL(lock_page);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
@@ -272,6 +281,7 @@
 EXPORT_SYMBOL(sync_dev);
 EXPORT_SYMBOL(devfs_register_partitions);
 EXPORT_SYMBOL(blkdev_open);
+EXPORT_SYMBOL(blkdev_close);
 EXPORT_SYMBOL(blkdev_get);
 EXPORT_SYMBOL(blkdev_put);
 EXPORT_SYMBOL(ioctl_by_bdev);
@@ -307,11 +317,12 @@
 EXPORT_SYMBOL(prepare_binprm);
 EXPORT_SYMBOL(compute_creds);
 EXPORT_SYMBOL(remove_arg_zero);
+EXPORT_SYMBOL(set_binfmt);
 
 /* execution environment registration */
-EXPORT_SYMBOL(lookup_exec_domain);
 EXPORT_SYMBOL(register_exec_domain);
 EXPORT_SYMBOL(unregister_exec_domain);
+EXPORT_SYMBOL(__set_personality);
 
 /* sysctl table registration */
 EXPORT_SYMBOL(register_sysctl_table);
@@ -398,6 +409,7 @@
 
 /* process management */
 EXPORT_SYMBOL(__wake_up);
+EXPORT_SYMBOL(wake_up_process);
 EXPORT_SYMBOL(sleep_on);
 EXPORT_SYMBOL(sleep_on_timeout);
 EXPORT_SYMBOL(interruptible_sleep_on);
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/panic.c linux/kernel/panic.c
--- v2.3.99-pre5/linux/kernel/panic.c	Tue Apr 11 15:09:25 2000
+++ linux/kernel/panic.c	Fri Apr 21 16:08:45 2000
@@ -65,7 +65,7 @@
 
 	unblank_console();
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
 
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/pm.c linux/kernel/pm.c
--- v2.3.99-pre5/linux/kernel/pm.c	Tue Mar 14 19:10:40 2000
+++ linux/kernel/pm.c	Wed Apr 12 09:47:29 2000
@@ -30,13 +30,13 @@
 
 /**
  *	pm_register - register a device with power management
- *	@type: The device type 
- *	@id: Device ID
- *	@callback: Callback function
+ *	@type: device type 
+ *	@id: device ID
+ *	@callback: callback function
  *
  *	Add a device to the list of devices that wish to be notified about
- *	power management events. A pm_dev structure is returnd on success,
- *	on failure the return is NULL
+ *	power management events. A &pm_dev structure is returned on success,
+ *	on failure the return is %NULL.
  */
  
 struct pm_dev *pm_register(pm_dev_t type,
@@ -113,8 +113,8 @@
  *	@data: data for the callback
  *
  *	Issue a power management request to a given device. The 
- *	PM_SUSPEND and PM_RESUME events are handled specially. The
- *	data field must hold the intented next state. No call is made
+ *	%PM_SUSPEND and %PM_RESUME events are handled specially. The
+ *	data field must hold the intended next state. No call is made
  *	if the state matches.
  *
  *	BUGS: what stops two power management requests occuring in parallel
@@ -171,12 +171,12 @@
 }
 
 /**
- *	pm_send - send request to all managed device
+ *	pm_send_all - send request to all managed devices
  *	@rqst: power management request
  *	@data: data for the callback
  *
  *	Issue a power management request to a all devices. The 
- *	PM_SUSPEND events are handled specially. Any device is 
+ *	%PM_SUSPEND events are handled specially. Any device is 
  *	permitted to fail a suspend by returning a non zero (error)
  *	value from its callback function. If any device vetoes a 
  *	suspend request then all other devices that have suspended 
@@ -214,14 +214,14 @@
 /**
  *	pm_find  - find a device
  *	@type: type of device
- *	@from: Where to start looking
+ *	@from: where to start looking
  *
  *	Scan the power management list for devices of a specific type. The
  *	return value for a matching device may be passed to further calls
- *	to this function to find further matches. A NULL indicates the end
+ *	to this function to find further matches. A %NULL indicates the end
  *	of the list. 
  *
- *	To search from the beginning pass NULL as the from value.
+ *	To search from the beginning pass %NULL as the @from value.
  */
  
 struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.3.99-pre5/linux/kernel/ptrace.c	Mon Mar 27 08:08:32 2000
+++ linux/kernel/ptrace.c	Mon Apr 24 15:42:19 2000
@@ -11,6 +11,7 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
+#include <linux/smp_lock.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -18,7 +19,7 @@
 /*
  * Access another process' address space, one page at a time.
  */
-static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
+static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
 {
 	pgd_t * pgdir;
 	pmd_t * pgmiddle;
@@ -65,7 +66,7 @@
 
 fault_in_page:
 	/* -1: out of memory. 0 - unmapped page */
-	if (handle_mm_fault(tsk, vma, addr, write) > 0)
+	if (handle_mm_fault(mm, vma, addr, write) > 0)
 		goto repeat;
 	return 0;
 
@@ -78,18 +79,10 @@
 	return 0;
 }
 
-int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+static int access_mm(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
 {
-	int copied;
-	struct vm_area_struct * vma;
+	int copied = 0;
 
-	down(&tsk->mm->mmap_sem);
-	vma = find_extend_vma(tsk, addr);
-	if (!vma) {
-		up(&tsk->mm->mmap_sem);
-		return 0;
-	}
-	copied = 0;
 	for (;;) {
 		unsigned long offset = addr & ~PAGE_MASK;
 		int this_len = PAGE_SIZE - offset;
@@ -97,7 +90,7 @@
 
 		if (this_len > len)
 			this_len = len;
-		retval = access_one_page(tsk, vma, addr, buf, this_len, write);
+		retval = access_one_page(mm, vma, addr, buf, this_len, write);
 		copied += retval;
 		if (retval != this_len)
 			break;
@@ -118,7 +111,29 @@
 	
 		vma = vma->vm_next;
 	}
-	up(&tsk->mm->mmap_sem);
+	return copied;
+}
+
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
+	int copied;
+	struct mm_struct *mm;
+	struct vm_area_struct * vma;
+
+	/* Worry about races with exit() */
+	lock_kernel();
+	mm = tsk->mm;
+	atomic_inc(&mm->mm_users);
+	unlock_kernel();
+
+	down(&mm->mmap_sem);
+	vma = find_extend_vma(mm, addr);
+	copied = 0;
+	if (vma)
+		copied = access_mm(mm, vma, addr, buf, len, write);
+
+	up(&mm->mmap_sem);
+	mmput(mm);
 	return copied;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.99-pre5/linux/kernel/sched.c	Tue Apr 11 15:09:25 2000
+++ linux/kernel/sched.c	Fri Apr 21 16:08:45 2000
@@ -19,6 +19,7 @@
  * current-task
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
@@ -80,7 +81,7 @@
 
 struct kernel_stat kstat = { 0 };
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #define idle_task(cpu) (init_tasks[cpu_number_map(cpu)])
 #define can_schedule(p)	(!(p)->has_cpu)
@@ -133,7 +134,7 @@
 	if (!weight)
 		goto out;
 			
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	/* Give a largish advantage to the same processor...   */
 	/* (this is equivalent to penalizing other processors) */
 	if (p->processor == this_cpu)
@@ -184,7 +185,7 @@
  */
 static inline void reschedule_idle(struct task_struct * p, unsigned long flags)
 {
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	int this_cpu = smp_processor_id(), target_cpu;
 	struct task_struct *tsk;
 	int cpu, best_cpu, i;
@@ -406,7 +407,7 @@
 static inline void __schedule_tail(struct task_struct *prev)
 {
 	current->need_resched |= prev->need_resched;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if ((prev->state == TASK_RUNNING) &&
 			(prev != idle_task(smp_processor_id()))) {
 		unsigned long flags;
@@ -416,7 +417,7 @@
 	}
 	wmb();
 	prev->has_cpu = 0;
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 }
 
 void schedule_tail(struct task_struct *prev)
@@ -516,7 +517,7 @@
 	 * sched_data.
 	 */
 	sched_data->curr = next;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
  	next->has_cpu = 1;
 	next->processor = this_cpu;
 #endif
@@ -525,7 +526,7 @@
 	if (prev == next)
 		goto same_process;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
  	/*
  	 * maintain the per-process 'average timeslice' value.
  	 * (this has to be recalculated even if we reschedule to
@@ -554,7 +555,7 @@
 	 * rescheduled during switch_to().
 	 */
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 	kstat.context_swtch++;
 	/*
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/sys.c linux/kernel/sys.c
--- v2.3.99-pre5/linux/kernel/sys.c	Sun Mar 19 18:35:31 2000
+++ linux/kernel/sys.c	Thu Apr 13 17:06:05 2000
@@ -927,7 +927,7 @@
 			? -EFAULT : 0;
 }
 
-#if !defined(__ia64__)
+#if !defined(__ia64__) && !defined(__s390__)
 
 /*
  *	Back compatibility for getrlimit. Needed for some apps.
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.3.99-pre5/linux/kernel/sysctl.c	Mon Mar 27 08:08:32 2000
+++ linux/kernel/sysctl.c	Fri Apr 21 16:11:02 2000
@@ -228,7 +228,7 @@
 static ctl_table vm_table[] = {
 	{VM_FREEPG, "freepages", 
 	 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
-	{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
+	{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
 	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
 	 &bdflush_min, &bdflush_max},
 	{VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
@@ -240,9 +240,9 @@
 	{VM_PAGERDAEMON, "kswapd",
 	 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
 	{VM_PGT_CACHE, "pagetable_cache", 
-	 &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
+	 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
 	{VM_PAGE_CLUSTER, "page-cluster", 
-	 &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec},
+	 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
@@ -320,6 +320,7 @@
 			kfree(context);
 		if (error != -ENOTDIR)
 			return error;
+		tmp = tmp->next;
 	} while (tmp != &root_table_header.ctl_entry);
 	return -ENOTDIR;
 }
@@ -365,14 +366,13 @@
 		       void *newval, size_t newlen,
 		       ctl_table *table, void **context)
 {
+	int n;
 repeat:
 	if (!nlen)
 		return -ENOTDIR;
-
+	if (get_user(n, name))
+		return -EFAULT;
 	for ( ; table->ctl_name; table++) {
-		int n;
-		if (get_user(n, name))
-			return -EFAULT;
 		if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
 			int error;
 			if (table->child) {
diff -u --recursive --new-file v2.3.99-pre5/linux/kernel/timer.c linux/kernel/timer.c
--- v2.3.99-pre5/linux/kernel/timer.c	Thu Feb 10 17:11:23 2000
+++ linux/kernel/timer.c	Fri Apr 21 16:08:45 2000
@@ -15,6 +15,7 @@
  *  1999-03-10  Improved NTP compatibility by Ulrich Windl
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/timex.h>
 #include <linux/delay.h>
@@ -211,7 +212,7 @@
 	return ret;
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /*
  * SMP specific function to delete periodic timer.
  * Caller must disable by some means restarting the timer
@@ -564,7 +565,7 @@
 /*
  * SMP does this on a per-CPU basis elsewhere
  */
-#ifndef  __SMP__
+#ifndef  CONFIG_SMP
 	struct task_struct * p = current;
 	unsigned long user = ticks - system;
 	if (p->pid) {
@@ -748,7 +749,7 @@
 	parent = me->p_opptr;
 	for (;;) {
 		pid = parent->pid;
-#if __SMP__
+#if CONFIG_SMP
 {
 		struct task_struct *old = parent;
 		mb();
diff -u --recursive --new-file v2.3.99-pre5/linux/lib/brlock.c linux/lib/brlock.c
--- v2.3.99-pre5/linux/lib/brlock.c	Thu Mar  2 14:36:23 2000
+++ linux/lib/brlock.c	Mon Apr 24 13:59:56 2000
@@ -25,7 +25,7 @@
 	int i;
 
 	for (i = 0; i < smp_num_cpus; i++)
-		write_lock(__brlock_array[idx] + i);
+		write_lock(__brlock_array[idx] + cpu_logical_map(i));
 }
 
 void __br_write_unlock (enum brlock_indices idx)
@@ -33,7 +33,7 @@
 	int i;
 
 	for (i = 0; i < smp_num_cpus; i++)
-		write_unlock(__brlock_array[idx] + i);
+		write_unlock(__brlock_array[idx] + cpu_logical_map(i));
 }
 
 #else /* ! __BRLOCK_USE_ATOMICS */
@@ -51,7 +51,7 @@
 	spin_lock(&__br_write_locks[idx].lock);
 again:
 	for (i = 0; i < smp_num_cpus; i++)
-		if (__brlock_array[i][idx] != 0)
+		if (__brlock_array[cpu_logical_map(i)][idx] != 0)
 			goto again;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.99-pre5/linux/mm/filemap.c	Tue Apr 11 15:09:25 2000
+++ linux/mm/filemap.c	Wed Apr 26 15:06:25 2000
@@ -44,6 +44,7 @@
 atomic_t page_cache_size = ATOMIC_INIT(0);
 unsigned int page_hash_bits;
 struct page **page_hash_table;
+struct list_head lru_cache;
 
 spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED;
 /*
@@ -77,6 +78,15 @@
 	atomic_dec(&page_cache_size);
 }
 
+static inline int sync_page(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+
+	if (mapping && mapping->a_ops && mapping->a_ops->sync_page)
+		return mapping->a_ops->sync_page(page);
+	return 0;
+}
+
 /*
  * Remove a page from the page cache and free it. Caller has to make
  * sure the page is locked and that nobody else uses it - or that usage
@@ -87,6 +97,9 @@
 	if (!PageLocked(page))
 		PAGE_BUG(page);
 
+	/* Initiate completion of any async operations */
+	sync_page(page);
+
 	spin_lock(&pagecache_lock);
 	remove_page_from_inode_queue(page);
 	remove_page_from_hash_queue(page);
@@ -99,6 +112,7 @@
 	struct list_head *head, *curr;
 	struct page * page;
 
+ repeat:
 	head = &inode->i_mapping->pages;
 	spin_lock(&pagecache_lock);
 	curr = head->next;
@@ -110,14 +124,13 @@
 		/* We cannot invalidate a locked page */
 		if (TryLockPage(page))
 			continue;
+		spin_unlock(&pagecache_lock);
 
 		lru_cache_del(page);
-		remove_page_from_inode_queue(page);
-		remove_page_from_hash_queue(page);
-		page->mapping = NULL;
+		remove_inode_page(page);
 		UnlockPage(page);
-
 		page_cache_release(page);
+		goto repeat;
 	}
 	spin_unlock(&pagecache_lock);
 }
@@ -149,11 +162,16 @@
 
 		/* page wholly truncated - free it */
 		if (offset >= start) {
+			if (TryLockPage(page)) {
+				spin_unlock(&pagecache_lock);
+				get_page(page);
+				wait_on_page(page);
+				put_page(page);
+				goto repeat;
+			}
 			get_page(page);
 			spin_unlock(&pagecache_lock);
 
-			lock_page(page);
-
 			if (!page->buffers || block_flushpage(page, 0))
 				lru_cache_del(page);
 
@@ -191,11 +209,13 @@
 			continue;
 
 		/* partial truncate, clear end of page */
+		if (TryLockPage(page)) {
+			spin_unlock(&pagecache_lock);
+			goto repeat;
+		}
 		get_page(page);
 		spin_unlock(&pagecache_lock);
 
-		lock_page(page);
-
 		memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
 		if (page->buffers)
 			block_flushpage(page, partial);
@@ -208,6 +228,9 @@
 		 */
 		UnlockPage(page);
 		page_cache_release(page);
+		get_page(page);
+		wait_on_page(page);
+		put_page(page);
 		goto repeat;
 	}
 	spin_unlock(&pagecache_lock);
@@ -215,46 +238,55 @@
 
 int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
 {
-	int ret = 0, count;
+	int ret = 0, loop = 0, count;
 	LIST_HEAD(young);
 	LIST_HEAD(old);
 	LIST_HEAD(forget);
 	struct list_head * page_lru, * dispose;
-	struct page * page;
-
+	struct page * page = NULL;
+	struct zone_struct * p_zone;
+	int maxloop = 256 >> priority;
+	
 	if (!zone)
 		BUG();
 
-	count = nr_lru_pages / (priority+1);
+	count = nr_lru_pages >> priority;
+	if (!count)
+		return ret;
 
 	spin_lock(&pagemap_lru_lock);
-
-	while (count > 0 && (page_lru = zone->lru_cache.prev) != &zone->lru_cache) {
+again:
+	/* we need pagemap_lru_lock for list_del() ... subtle code below */
+	while (count > 0 && (page_lru = lru_cache.prev) != &lru_cache) {
 		page = list_entry(page_lru, struct page, lru);
 		list_del(page_lru);
+		p_zone = page->zone;
 
-		dispose = &zone->lru_cache;
-		if (test_and_clear_bit(PG_referenced, &page->flags))
-			/* Roll the page at the top of the lru list,
-			 * we could also be more aggressive putting
-			 * the page in the young-dispose-list, so
-			 * avoiding to free young pages in each pass.
-			 */
-			goto dispose_continue;
-
+		/*
+		 * These two tests are there to make sure we don't free too
+		 * many pages from the "wrong" zone. We free some anyway,
+		 * they are the least recently used pages in the system.
+		 * When we don't free them, leave them in &old.
+		 */
 		dispose = &old;
-		/* don't account passes over not DMA pages */
-		if (zone && (!memclass(page->zone, zone)))
+		if (p_zone != zone && (loop > (maxloop / 4) ||
+				p_zone->free_pages > p_zone->pages_high))
 			goto dispose_continue;
 
-		count--;
-
+		/* The page is in use, or was used very recently, put it in
+		 * &young to make sure that we won't try to free it the next
+		 * time */
 		dispose = &young;
 
-		/* avoid unscalable SMP locking */
+		if (test_and_clear_bit(PG_referenced, &page->flags))
+			goto dispose_continue;
+
+		count--;
 		if (!page->buffers && page_count(page) > 1)
 			goto dispose_continue;
 
+		/* Page not used -> free it; if that fails -> &old */
+		dispose = &old;
 		if (TryLockPage(page))
 			goto dispose_continue;
 
@@ -327,6 +359,7 @@
 		list_add(page_lru, dispose);
 		continue;
 
+		/* we're holding pagemap_lru_lock, so we can just loop again */
 dispose_continue:
 		list_add(page_lru, dispose);
 	}
@@ -342,9 +375,14 @@
 	/* nr_lru_pages needs the spinlock */
 	nr_lru_pages--;
 
+	loop++;
+	/* wrong zone?  not looped too often?    roll again... */
+	if (page->zone != zone && loop < maxloop)
+		goto again;
+
 out:
-	list_splice(&young, &zone->lru_cache);
-	list_splice(&old, zone->lru_cache.prev);
+	list_splice(&young, &lru_cache);
+	list_splice(&old, lru_cache.prev);
 
 	spin_unlock(&pagemap_lru_lock);
 
@@ -467,6 +505,9 @@
 	struct page *alias;
 	unsigned long flags;
 
+	if (PageLocked(page))
+		BUG();
+
 	flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty));
 	page->flags = flags | (1 << PG_locked) | (1 << PG_referenced);
 	get_page(page);
@@ -574,7 +615,7 @@
 
 	add_wait_queue(&page->wait, &wait);
 	do {
-		run_task_queue(&tq_disk);
+		sync_page(page);
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 		if (!PageLocked(page))
 			break;
@@ -619,7 +660,7 @@
 		struct task_struct *tsk = current;
 		DECLARE_WAITQUEUE(wait, tsk);
 
-		run_task_queue(&tq_disk);
+		sync_page(page);
 
 		__set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&page->wait, &wait);
@@ -669,7 +710,7 @@
 		struct task_struct *tsk = current;
 		DECLARE_WAITQUEUE(wait, tsk);
 
-		run_task_queue(&tq_disk);
+		sync_page(page);
 
 		__set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&page->wait, &wait);
@@ -1496,7 +1537,7 @@
 	 * mmap_sem is held.
 	 */
 	lock_page(page);
-	result = inode->i_mapping->a_ops->writepage(dentry, page);
+	result = inode->i_mapping->a_ops->writepage(file, dentry, page);
 	UnlockPage(page);
 	return result;
 }
@@ -1707,8 +1748,8 @@
 		error = vma->vm_ops->sync(vma, start, end-start, flags);
 		if (!error && (flags & MS_SYNC)) {
 			struct file * file = vma->vm_file;
-			if (file)
-				error = file_fsync(file, file->f_dentry);
+			if (file && file->f_op && file->f_op->fsync)
+				error = file->f_op->fsync(file, file->f_dentry);
 		}
 		return error;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/memory.c linux/mm/memory.c
--- v2.3.99-pre5/linux/mm/memory.c	Tue Apr 11 15:09:25 2000
+++ linux/mm/memory.c	Mon Apr 24 15:46:18 2000
@@ -472,7 +472,7 @@
 				goto out_unlock;
 			}
 		}
-		if (handle_mm_fault(current, vma, ptr, datain) <= 0) 
+		if (handle_mm_fault(current->mm, vma, ptr, datain) <= 0) 
 			goto out_unlock;
 		spin_lock(&mm->page_table_lock);
 		map = follow_page(ptr);
@@ -815,7 +815,7 @@
  * We enter with the page table read-lock held, and need to exit without
  * it.
  */
-static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
 	unsigned long address, pte_t *page_table, pte_t pte)
 {
 	unsigned long map_nr;
@@ -824,7 +824,7 @@
 	map_nr = pte_pagenr(pte);
 	if (map_nr >= max_mapnr)
 		goto bad_wp_page;
-	tsk->min_flt++;
+	mm->min_flt++;
 	old_page = mem_map + map_nr;
 	
 	/*
@@ -854,36 +854,36 @@
 	case 1:
 		flush_cache_page(vma, address);
 		establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
-		spin_unlock(&tsk->mm->page_table_lock);
+		spin_unlock(&mm->page_table_lock);
 		return 1;
 	}
 
 	/*
 	 * Ok, we need to copy. Oh, well..
 	 */
-	spin_unlock(&tsk->mm->page_table_lock);
+	spin_unlock(&mm->page_table_lock);
 	new_page = alloc_page(GFP_HIGHUSER);
 	if (!new_page)
 		return -1;
-	spin_lock(&tsk->mm->page_table_lock);
+	spin_lock(&mm->page_table_lock);
 
 	/*
 	 * Re-check the pte - we dropped the lock
 	 */
 	if (pte_val(*page_table) == pte_val(pte)) {
 		if (PageReserved(old_page))
-			++vma->vm_mm->rss;
+			++mm->rss;
 		break_cow(vma, old_page, new_page, address, page_table);
 
 		/* Free the old page.. */
 		new_page = old_page;
 	}
-	spin_unlock(&tsk->mm->page_table_lock);
+	spin_unlock(&mm->page_table_lock);
 	__free_page(new_page);
 	return 1;
 
 bad_wp_page:
-	spin_unlock(&tsk->mm->page_table_lock);
+	spin_unlock(&mm->page_table_lock);
 	printk("do_wp_page: bogus page at address %08lx (nr %ld)\n",address,map_nr);
 	return -1;
 }
@@ -1029,7 +1029,7 @@
 	return;
 }
 
-static int do_swap_page(struct task_struct * tsk,
+static int do_swap_page(struct mm_struct * mm,
 	struct vm_area_struct * vma, unsigned long address,
 	pte_t * page_table, swp_entry_t entry, int write_access)
 {
@@ -1048,8 +1048,8 @@
 		flush_icache_page(vma, page);
 	}
 
-	vma->vm_mm->rss++;
-	tsk->min_flt++;
+	mm->rss++;
+	mm->min_flt++;
 
 	pte = mk_pte(page, vma->vm_page_prot);
 
@@ -1080,7 +1080,7 @@
 /*
  * This only needs the MM semaphore
  */
-static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
+static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
 {
 	int high = 0;
 	struct page *page = NULL;
@@ -1093,8 +1093,8 @@
 			high = 1;
 		clear_user_highpage(page, addr);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-		vma->vm_mm->rss++;
-		tsk->min_flt++;
+		mm->rss++;
+		mm->min_flt++;
 		flush_page_to_ram(page);
 	}
 	set_pte(page_table, entry);
@@ -1114,14 +1114,14 @@
  *
  * This is called with the MM semaphore held.
  */
-static int do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
 	unsigned long address, int write_access, pte_t *page_table)
 {
 	struct page * new_page;
 	pte_t entry;
 
 	if (!vma->vm_ops || !vma->vm_ops->nopage)
-		return do_anonymous_page(tsk, vma, page_table, write_access, address);
+		return do_anonymous_page(mm, vma, page_table, write_access, address);
 
 	/*
 	 * The third argument is "no_share", which tells the low-level code
@@ -1133,8 +1133,8 @@
 		return 0;
 	if (new_page == NOPAGE_OOM)
 		return -1;
-	++tsk->maj_flt;
-	++vma->vm_mm->rss;
+	++mm->maj_flt;
+	++mm->rss;
 	/*
 	 * This silly early PAGE_DIRTY setting removes a race
 	 * due to the bad i386 page protection. But it's valid
@@ -1177,7 +1177,7 @@
  * so we don't need to worry about a page being suddenly been added into
  * our VM.
  */
-static inline int handle_pte_fault(struct task_struct *tsk,
+static inline int handle_pte_fault(struct mm_struct *mm,
 	struct vm_area_struct * vma, unsigned long address,
 	int write_access, pte_t * pte)
 {
@@ -1186,8 +1186,8 @@
 	entry = *pte;
 	if (!pte_present(entry)) {
 		if (pte_none(entry))
-			return do_no_page(tsk, vma, address, write_access, pte);
-		return do_swap_page(tsk, vma, address, pte, pte_to_swp_entry(entry), write_access);
+			return do_no_page(mm, vma, address, write_access, pte);
+		return do_swap_page(mm, vma, address, pte, pte_to_swp_entry(entry), write_access);
 	}
 
 	/*
@@ -1195,38 +1195,38 @@
 	 * lock to synchronize with kswapd, and verify that the entry
 	 * didn't change from under us..
 	 */
-	spin_lock(&tsk->mm->page_table_lock);
+	spin_lock(&mm->page_table_lock);
 	if (pte_val(entry) == pte_val(*pte)) {
 		if (write_access) {
 			if (!pte_write(entry))
-				return do_wp_page(tsk, vma, address, pte, entry);
+				return do_wp_page(mm, vma, address, pte, entry);
 
 			entry = pte_mkdirty(entry);
 		}
 		entry = pte_mkyoung(entry);
 		establish_pte(vma, address, pte, entry);
 	}
-	spin_unlock(&tsk->mm->page_table_lock);
+	spin_unlock(&mm->page_table_lock);
 	return 1;
 }
 
 /*
  * By the time we get here, we already hold the mm semaphore
  */
-int handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
+int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
 	unsigned long address, int write_access)
 {
 	int ret = -1;
 	pgd_t *pgd;
 	pmd_t *pmd;
 
-	pgd = pgd_offset(vma->vm_mm, address);
+	pgd = pgd_offset(mm, address);
 	pmd = pmd_alloc(pgd, address);
 	
 	if (pmd) {
 		pte_t * pte = pte_alloc(pmd, address);
 		if (pte)
-			ret = handle_pte_fault(tsk, vma, address, write_access, pte);
+			ret = handle_pte_fault(mm, vma, address, write_access, pte);
 	}
 	return ret;
 }
@@ -1237,15 +1237,15 @@
 int make_pages_present(unsigned long addr, unsigned long end)
 {
 	int write;
-	struct task_struct *tsk = current;
+	struct mm_struct *mm = current->mm;
 	struct vm_area_struct * vma;
 
-	vma = find_vma(tsk->mm, addr);
+	vma = find_vma(mm, addr);
 	write = (vma->vm_flags & VM_WRITE) != 0;
 	if (addr >= end)
 		BUG();
 	do {
-		if (handle_mm_fault(tsk, vma, addr, write) < 0)
+		if (handle_mm_fault(mm, vma, addr, write) < 0)
 			return -1;
 		addr += PAGE_SIZE;
 	} while (addr < end);
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.99-pre5/linux/mm/mmap.c	Mon Mar 27 08:08:33 2000
+++ linux/mm/mmap.c	Wed Apr 26 09:11:32 2000
@@ -110,7 +110,7 @@
 
 	/* Always allow shrinking brk. */
 	if (brk <= mm->brk) {
-		if (!do_munmap(newbrk, oldbrk-newbrk))
+		if (!do_munmap(mm, newbrk, oldbrk-newbrk))
 			goto set_brk;
 		goto out;
 	}
@@ -220,8 +220,7 @@
 		default:
 			return -EINVAL;
 		}
-	} else if ((flags & MAP_TYPE) != MAP_PRIVATE)
-		return -EINVAL;
+	}
 
 	/* Obtain the address to map to. we verify (or select) it and ensure
 	 * that it represents a valid section of the address space.
@@ -269,8 +268,11 @@
 			if (!(file->f_mode & FMODE_WRITE))
 				vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
 		}
-	} else
+	} else {
 		vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+		if (flags & MAP_SHARED)
+			vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
+	}
 	vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
 	vma->vm_ops = NULL;
 	vma->vm_pgoff = pgoff;
@@ -279,7 +281,7 @@
 
 	/* Clear old maps */
 	error = -ENOMEM;
-	if (do_munmap(addr, len))
+	if (do_munmap(mm, addr, len))
 		goto free_vma;
 
 	/* Check against address space limit. */
@@ -316,6 +318,8 @@
 			atomic_inc(&file->f_dentry->d_inode->i_writecount);
 		if (error)
 			goto unmap_and_free_vma;
+	} else if (flags & MAP_SHARED) {
+		error = map_zero_setup(vma);
 	}
 
 	/*
@@ -468,13 +472,13 @@
 	return NULL;
 }
 
-struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
+struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
 {
 	struct vm_area_struct * vma;
 	unsigned long start;
 
 	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm,addr);
+	vma = find_vma(mm,addr);
 	if (!vma)
 		return NULL;
 	if (vma->vm_start <= addr)
@@ -513,8 +517,9 @@
  * allocate a new one, and the return indicates whether the old
  * area was reused.
  */
-static struct vm_area_struct * unmap_fixup(struct vm_area_struct *area,
-	unsigned long addr, size_t len, struct vm_area_struct *extra)
+static struct vm_area_struct * unmap_fixup(struct mm_struct *mm, 
+	struct vm_area_struct *area, unsigned long addr, size_t len, 
+	struct vm_area_struct *extra)
 {
 	struct vm_area_struct *mpnt;
 	unsigned long end = addr + len;
@@ -536,11 +541,11 @@
 	/* Work out to one of the ends. */
 	if (end == area->vm_end) {
 		area->vm_end = addr;
-		vmlist_modify_lock(current->mm);
+		vmlist_modify_lock(mm);
 	} else if (addr == area->vm_start) {
 		area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT;
 		area->vm_start = end;
-		vmlist_modify_lock(current->mm);
+		vmlist_modify_lock(mm);
 	} else {
 	/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
 		/* Add end mapping -- leave beginning for below */
@@ -562,12 +567,12 @@
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
-		vmlist_modify_lock(current->mm);
-		insert_vm_struct(current->mm, mpnt);
+		vmlist_modify_lock(mm);
+		insert_vm_struct(mm, mpnt);
 	}
 
-	insert_vm_struct(current->mm, area);
-	vmlist_modify_unlock(current->mm);
+	insert_vm_struct(mm, area);
+	vmlist_modify_unlock(mm);
 	return extra;
 }
 
@@ -634,9 +639,8 @@
  * work.  This now handles partial unmappings.
  * Jeremy Fitzhardine <jeremy@sw.oz.au>
  */
-int do_munmap(unsigned long addr, size_t len)
+int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
 {
-	struct mm_struct * mm;
 	struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;
 
 	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
@@ -650,7 +654,6 @@
 	 * every area affected in some way (by any overlap) is put
 	 * on the list.  If nothing is put on, nothing is affected.
 	 */
-	mm = current->mm;
 	mpnt = find_vma_prev(mm, addr, &prev);
 	if (!mpnt)
 		return 0;
@@ -713,7 +716,7 @@
 		/*
 		 * Fix the mapping, and free the old area if it wasn't reused.
 		 */
-		extra = unmap_fixup(mpnt, st, size, extra);
+		extra = unmap_fixup(mm, mpnt, st, size, extra);
 	}
 
 	/* Release the extra vma struct if it wasn't used */
@@ -728,10 +731,11 @@
 asmlinkage long sys_munmap(unsigned long addr, size_t len)
 {
 	int ret;
+	struct mm_struct *mm = current->mm;
 
-	down(&current->mm->mmap_sem);
-	ret = do_munmap(addr, len);
-	up(&current->mm->mmap_sem);
+	down(&mm->mmap_sem);
+	ret = do_munmap(mm, addr, len);
+	up(&mm->mmap_sem);
 	return ret;
 }
 
@@ -763,7 +767,7 @@
 	/*
 	 * Clear old maps.  this also does some error checking for us
 	 */
-	retval = do_munmap(addr, len);
+	retval = do_munmap(mm, addr, len);
 	if (retval != 0)
 		return retval;
 
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/mremap.c linux/mm/mremap.c
--- v2.3.99-pre5/linux/mm/mremap.c	Tue Mar 14 19:10:40 2000
+++ linux/mm/mremap.c	Wed Apr 26 09:16:39 2000
@@ -145,7 +145,7 @@
 			insert_vm_struct(current->mm, new_vma);
 			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
 			vmlist_modify_unlock(vma->vm_mm);
-			do_munmap(addr, old_len);
+			do_munmap(current->mm, addr, old_len);
 			current->mm->total_vm += new_len >> PAGE_SHIFT;
 			if (new_vma->vm_flags & VM_LOCKED) {
 				current->mm->locked_vm += new_len >> PAGE_SHIFT;
@@ -201,7 +201,7 @@
 		if ((addr <= new_addr) && (addr+old_len) > new_addr)
 			goto out;
 
-		do_munmap(new_addr, new_len);
+		do_munmap(current->mm, new_addr, new_len);
 	}
 
 	/*
@@ -210,7 +210,7 @@
 	 */
 	ret = addr;
 	if (old_len >= new_len) {
-		do_munmap(addr+new_len, old_len - new_len);
+		do_munmap(current->mm, addr+new_len, old_len - new_len);
 		if (!(flags & MREMAP_FIXED) || (new_addr == addr))
 			goto out;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.99-pre5/linux/mm/page_alloc.c	Tue Apr 11 15:09:25 2000
+++ linux/mm/page_alloc.c	Wed Apr 26 15:06:25 2000
@@ -25,7 +25,7 @@
 #endif
 
 int nr_swap_pages = 0;
-int nr_lru_pages;
+int nr_lru_pages = 0;
 pg_data_t *pgdat_list = (pg_data_t *)0;
 
 static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
@@ -273,6 +273,8 @@
 struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
 {
 	zone_t **zone = zonelist->zones;
+	int gfp_mask = zonelist->gfp_mask;
+	static int low_on_memory;
 
 	/*
 	 * If this is a recursive call, we'd better
@@ -282,6 +284,11 @@
 	if (current->flags & PF_MEMALLOC)
 		goto allocate_ok;
 
+	/* If we're a memory hog, unmap some pages */
+	if (current->hog && low_on_memory &&
+			(gfp_mask & __GFP_WAIT))
+		swap_out(4, gfp_mask);
+
 	/*
 	 * (If anyone calls gfp from interrupts nonatomically then it
 	 * will sooner or later tripped up by a schedule().)
@@ -299,11 +306,13 @@
 		/* Are we supposed to free memory? Don't make it worse.. */
 		if (!z->zone_wake_kswapd && z->free_pages > z->pages_low) {
 			struct page *page = rmqueue(z, order);
+			low_on_memory = 0;
 			if (page)
 				return page;
 		}
 	}
 
+	low_on_memory = 1;
 	/*
 	 * Ok, no obvious zones were available, start
 	 * balancing things a bit..
@@ -530,6 +539,7 @@
 	freepages.min += i;
 	freepages.low += i * 2;
 	freepages.high += i * 3;
+	memlist_init(&lru_cache);
 
 	/*
 	 * Some architectures (with lots of mem and discontinous memory
@@ -609,7 +619,6 @@
 			unsigned long bitmap_size;
 
 			memlist_init(&zone->free_area[i].free_list);
-			memlist_init(&zone->lru_cache);
 			mask += mask;
 			size = (size + ~mask) & mask;
 			bitmap_size = size >> i;
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/slab.c linux/mm/slab.c
--- v2.3.99-pre5/linux/mm/slab.c	Tue Apr 11 15:09:25 2000
+++ linux/mm/slab.c	Wed Apr 12 09:12:35 2000
@@ -1529,7 +1529,7 @@
  * it should be in this state _before_ it is released.
  */
 static inline void
-__kmem_cache_free(kmem_cache_t *cachep, const void *objp)
+__kmem_cache_free(kmem_cache_t *cachep, void *objp)
 {
 	kmem_slab_t	*slabp;
 	kmem_bufctl_t	*bufp;
@@ -1722,7 +1722,7 @@
 		 */
 		cachep = SLAB_GET_PAGE_CACHE(page);
 		if (cachep && (cachep->c_flags & SLAB_CFLGS_GENERAL)) {
-			__kmem_cache_free(cachep, objp);
+			__kmem_cache_free(cachep, (void *)objp);
 			return;
 		}
 	}
@@ -1757,7 +1757,7 @@
 		cachep = SLAB_GET_PAGE_CACHE(page);
 		if (cachep && cachep->c_flags & SLAB_CFLGS_GENERAL) {
 			if (size <= cachep->c_org_size) {	/* XXX better check */
-				__kmem_cache_free(cachep, objp);
+				__kmem_cache_free(cachep, (void *)objp);
 				return;
 			}
 		}
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.3.99-pre5/linux/mm/swap_state.c	Tue Apr 11 15:09:25 2000
+++ linux/mm/swap_state.c	Tue Apr 25 17:28:56 2000
@@ -17,12 +17,17 @@
 
 #include <asm/pgtable.h>
 
+static struct address_space_operations swap_aops = {
+	sync_page: block_sync_page
+};
+
 struct address_space swapper_space = {
 	{				/* pages	*/
 		&swapper_space.pages,	/*        .next */
 		&swapper_space.pages	/*	  .prev */
 	},
-	0				/* nrpages	*/
+	0,				/* nrpages	*/
+	&swap_aops,
 };
 
 #ifdef SWAP_CACHE_INFO
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.99-pre5/linux/mm/swapfile.c	Tue Apr 11 15:09:26 2000
+++ linux/mm/swapfile.c	Fri Apr 21 13:36:40 2000
@@ -444,6 +444,7 @@
 {
 	struct swap_info_struct * p = NULL;
 	struct dentry * dentry;
+	struct vfsmount *mnt;
 	int i, type, prev;
 	int err;
 	
@@ -513,11 +514,14 @@
 
 	dentry = p->swap_file;
 	p->swap_file = NULL;
+	mnt = p->swap_vfsmnt;
+	p->swap_vfsmnt = NULL;
 	p->swap_device = 0;
 	vfree(p->swap_map);
 	p->swap_map = NULL;
 	p->flags = 0;
 	err = 0;
+	mntput(mnt);
 
 out_dput:
 	dput(dentry);
@@ -538,7 +542,8 @@
 	len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
 		if (ptr->flags & SWP_USED) {
-			char * path = d_path(ptr->swap_file, NULL, page, PAGE_SIZE);
+			char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
+						page, PAGE_SIZE);
 
 			len += sprintf(buf + len, "%-31s ", path);
 
@@ -584,7 +589,8 @@
 asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
 {
 	struct swap_info_struct * p;
-	struct dentry * swap_dentry;
+	struct nameidata nd;
+	struct inode * swap_inode;
 	unsigned int type;
 	int i, j, prev;
 	int error;
@@ -595,6 +601,7 @@
 	unsigned long maxpages;
 	int swapfilesize;
 	struct block_device *bdev = NULL;
+	char *name;
 	
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -610,6 +617,7 @@
 		nr_swapfiles = type+1;
 	p->flags = SWP_USED;
 	p->swap_file = NULL;
+	p->swap_vfsmnt = NULL;
 	p->swap_device = 0;
 	p->swap_map = NULL;
 	p->lowest_bit = 0;
@@ -624,24 +632,31 @@
 	} else {
 		p->prio = --least_priority;
 	}
-	swap_dentry = namei(specialfile);
-	error = PTR_ERR(swap_dentry);
-	if (IS_ERR(swap_dentry))
+	name = getname(specialfile);
+	error = PTR_ERR(name);
+	if (IS_ERR(name))
+		goto bad_swap_2;
+	error = 0;
+	if (walk_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
+		error = walk_name(name, &nd);
+	putname(name);
+	if (error)
 		goto bad_swap_2;
 
-	p->swap_file = swap_dentry;
+	p->swap_file = nd.dentry;
+	p->swap_vfsmnt = nd.mnt;
+	swap_inode = nd.dentry->d_inode;
 	error = -EINVAL;
 
-	if (S_ISBLK(swap_dentry->d_inode->i_mode)) {
-		kdev_t dev = swap_dentry->d_inode->i_rdev;
+	if (S_ISBLK(swap_inode->i_mode)) {
+		kdev_t dev = swap_inode->i_rdev;
 		struct block_device_operations *bdops;
 
 		p->swap_device = dev;
 		set_blocksize(dev, PAGE_SIZE);
 		
-		bdev = swap_dentry->d_inode->i_bdev;
-		bdops = devfs_get_ops ( devfs_get_handle_from_inode
-					(swap_dentry->d_inode) );
+		bdev = swap_inode->i_bdev;
+		bdops = devfs_get_ops(devfs_get_handle_from_inode(swap_inode));
 		if (bdops) bdev->bd_op = bdops;
 
 		error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
@@ -663,15 +678,15 @@
 		if (blk_size[MAJOR(dev)])
 			swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
 				>> (PAGE_SHIFT - 10);
-	} else if (S_ISREG(swap_dentry->d_inode->i_mode)) {
+	} else if (S_ISREG(swap_inode->i_mode)) {
 		error = -EBUSY;
 		for (i = 0 ; i < nr_swapfiles ; i++) {
 			if (i == type || !swap_info[i].swap_file)
 				continue;
-			if (swap_dentry->d_inode == swap_info[i].swap_file->d_inode)
+			if (swap_inode == swap_info[i].swap_file->d_inode)
 				goto bad_swap;
 		}
-		swapfilesize = swap_dentry->d_inode->i_size >> PAGE_SHIFT;
+		swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
 	} else
 		goto bad_swap;
 
@@ -811,13 +826,17 @@
 bad_swap_2:
 	if (p->swap_map)
 		vfree(p->swap_map);
-	dput(p->swap_file);
+	nd.mnt = p->swap_vfsmnt;
+	nd.dentry = p->swap_file;
 	p->swap_device = 0;
 	p->swap_file = NULL;
+	p->swap_vfsmnt = NULL;
 	p->swap_map = NULL;
 	p->flags = 0;
 	if (!(swap_flags & SWAP_FLAG_PREFER))
 		++least_priority;
+	dput(nd.dentry);
+	mntput(nd.mnt);
 out:
 	if (swap_header)
 		free_page((long) swap_header);
diff -u --recursive --new-file v2.3.99-pre5/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.99-pre5/linux/mm/vmscan.c	Tue Apr 11 15:09:26 2000
+++ linux/mm/vmscan.c	Wed Apr 26 15:13:01 2000
@@ -34,7 +34,7 @@
  * using a process that no longer actually exists (it might
  * have died while we slept).
  */
-static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask)
+static int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask)
 {
 	pte_t pte;
 	swp_entry_t entry;
@@ -48,6 +48,7 @@
 	if ((page-mem_map >= max_mapnr) || PageReserved(page))
 		goto out_failed;
 
+	mm->swap_cnt--;
 	/* Don't look at this pte if it's been accessed recently. */
 	if (pte_young(pte)) {
 		/*
@@ -194,7 +195,7 @@
  * (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de
  */
 
-static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
+static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
 {
 	pte_t * pte;
 	unsigned long pmd_end;
@@ -216,16 +217,18 @@
 	do {
 		int result;
 		vma->vm_mm->swap_address = address + PAGE_SIZE;
-		result = try_to_swap_out(vma, address, pte, gfp_mask);
+		result = try_to_swap_out(mm, vma, address, pte, gfp_mask);
 		if (result)
 			return result;
+		if (!mm->swap_cnt)
+			return 0;
 		address += PAGE_SIZE;
 		pte++;
 	} while (address && (address < end));
 	return 0;
 }
 
-static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
+static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
 {
 	pmd_t * pmd;
 	unsigned long pgd_end;
@@ -245,16 +248,18 @@
 		end = pgd_end;
 	
 	do {
-		int result = swap_out_pmd(vma, pmd, address, end, gfp_mask);
+		int result = swap_out_pmd(mm, vma, pmd, address, end, gfp_mask);
 		if (result)
 			return result;
+		if (!mm->swap_cnt)
+			return 0;
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address && (address < end));
 	return 0;
 }
 
-static int swap_out_vma(struct vm_area_struct * vma, unsigned long address, int gfp_mask)
+static int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int gfp_mask)
 {
 	pgd_t *pgdir;
 	unsigned long end;
@@ -269,9 +274,11 @@
 	if (address >= end)
 		BUG();
 	do {
-		int result = swap_out_pgd(vma, pgdir, address, end, gfp_mask);
+		int result = swap_out_pgd(mm, vma, pgdir, address, end, gfp_mask);
 		if (result)
 			return result;
+		if (!mm->swap_cnt)
+			return 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		pgdir++;
 	} while (address && (address < end));
@@ -299,7 +306,7 @@
 			address = vma->vm_start;
 
 		for (;;) {
-			int result = swap_out_vma(vma, address, gfp_mask);
+			int result = swap_out_vma(mm, vma, address, gfp_mask);
 			if (result)
 				return result;
 			vma = vma->vm_next;
@@ -321,7 +328,7 @@
  * N.B. This function returns only 0 or 1.  Return values != 1 from
  * the lower level routines result in continued processing.
  */
-static int swap_out(unsigned int priority, int gfp_mask)
+int swap_out(unsigned int priority, int gfp_mask)
 {
 	struct task_struct * p;
 	int counter;
@@ -356,6 +363,7 @@
 		p = init_task.next_task;
 		for (; p != &init_task; p = p->next_task) {
 			struct mm_struct *mm = p->mm;
+			p->hog = 0;
 			if (!p->swappable || !mm)
 				continue;
 	 		if (mm->rss <= 0)
@@ -369,9 +377,26 @@
 				pid = p->pid;
 			}
 		}
-		read_unlock(&tasklist_lock);
-		if (assign == 1)
+		if (assign == 1) {
+			/* we just assigned swap_cnt, normalise values */
 			assign = 2;
+			p = init_task.next_task;
+			for (; p != &init_task; p = p->next_task) {
+				int i = 0;
+				struct mm_struct *mm = p->mm;
+				if (!p->swappable || !mm || mm->rss <= 0)
+					continue;
+				/* small processes are swapped out less */
+				while ((mm->swap_cnt << 2 * (i + 1) < max_cnt))
+					i++;
+				mm->swap_cnt >>= i;
+				mm->swap_cnt += i; /* if swap_cnt reaches 0 */
+				/* we're big -> hog treatment */
+				if (!i)
+					p->hog = 1;
+			}
+		}
+		read_unlock(&tasklist_lock);
 		if (!best) {
 			if (!assign) {
 				assign = 1;
@@ -412,13 +437,14 @@
 {
 	int priority;
 	int count = SWAP_CLUSTER_MAX;
+	int ret;
 
 	/* Always trim SLAB caches when memory gets low. */
 	kmem_cache_reap(gfp_mask);
 
 	priority = 6;
 	do {
-		while (shrink_mmap(priority, gfp_mask, zone)) {
+		while ((ret = shrink_mmap(priority, gfp_mask, zone))) {
 			if (!--count)
 				goto done;
 		}
@@ -441,7 +467,9 @@
 			}
 		}
 
-		/* Then, try to page stuff out.. */
+		/* Then, try to page stuff out..
+		 * We use swapcount here because this doesn't actually
+		 * free pages */
 		while (swap_out(priority, gfp_mask)) {
 			if (!--count)
 				goto done;
diff -u --recursive --new-file v2.3.99-pre5/linux/net/802/tr.c linux/net/802/tr.c
--- v2.3.99-pre5/linux/net/802/tr.c	Mon Mar 27 08:08:33 2000
+++ linux/net/802/tr.c	Thu Apr 13 17:19:57 2000
@@ -266,7 +266,7 @@
 		if(entry) 
 		{
 #if TR_SR_DEBUG
-printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0],
+printk("source routing for %02X:%02X:%02X:%02X:%02X:%02X\n",trh->daddr[0],
 		  trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]);
 #endif
 			if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.3.99-pre5/linux/net/appletalk/ddp.c	Tue Mar 14 19:10:40 2000
+++ linux/net/appletalk/ddp.c	Mon Apr 24 13:43:04 2000
@@ -292,7 +292,7 @@
 		if (pos > offset + length)	/* We have dumped enough */
 			break;
 	}
-	spin_lock_bh(&atalk_sockets_lock);
+	spin_unlock_bh(&atalk_sockets_lock);
 
 	/* The data in question runs from begin to begin+len */
 	*start = buffer + (offset - begin);	/* Start of wanted data */
@@ -2055,24 +2055,23 @@
 
 static struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops)=
 {
-	PF_APPLETALK,
+	family:		PF_APPLETALK,
 
-	atalk_release,
-	atalk_bind,
-	atalk_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	atalk_getname,
-	datagram_poll,
-	atalk_ioctl,
-	sock_no_listen,
-	sock_no_shutdown,
-	sock_no_setsockopt,
-	sock_no_getsockopt,
-	sock_no_fcntl,
-	atalk_sendmsg,
-	atalk_recvmsg,
-	sock_no_mmap
+	release:	atalk_release,
+	bind:		atalk_bind,
+	connect:	atalk_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	atalk_getname,
+	poll:		datagram_poll,
+	ioctl:		atalk_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	sock_no_setsockopt,
+	getsockopt:	sock_no_getsockopt,
+	sendmsg:	atalk_sendmsg,
+	recvmsg:	atalk_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/clip.c linux/net/atm/clip.c
--- v2.3.99-pre5/linux/net/atm/clip.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/clip.c	Fri Apr 14 09:37:20 2000
@@ -172,7 +172,7 @@
 	DPRINTK("clip_arp_rcv\n");
 	vcc = ATM_SKB(skb)->vcc;
 	if (!vcc || !atm_charge(vcc,skb->truesize)) {
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		return 0;
 	}
 	DPRINTK("pushing to %p\n",vcc);
@@ -197,9 +197,8 @@
 	atm_return(vcc,skb->truesize);
 	skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
 		/* clip_vcc->entry == NULL if we don't have an IP address yet */
-	skb->rx_dev = NULL;
 	if (!skb->dev) {
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		return;
 	}
 	ATM_SKB(skb)->vcc = vcc;
@@ -232,18 +231,20 @@
 static void clip_pop(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
+	struct net_device *dev = skb->dev;
 	int old;
+	unsigned long flags;
 
 	DPRINTK("clip_pop(vcc %p)\n",vcc);
 	clip_vcc->old_pop(vcc,skb);
 	/* skb->dev == NULL in outbound ARP packets */
-	if (!skb->dev) return;
-	spin_lock(&PRIV(skb->dev)->xoff_lock);
+	if (!dev) return;
+	spin_lock_irqsave(&PRIV(dev)->xoff_lock,flags);
 	if (atm_may_send(vcc,0)) {
 		old = xchg(&clip_vcc->xoff,0);
-		if (old) netif_wake_queue(skb->dev);
+		if (old) netif_wake_queue(dev);
 	}
-	spin_unlock(&PRIV(skb->dev)->xoff_lock);
+	spin_unlock_irqrestore(&PRIV(dev)->xoff_lock,flags);
 }
 
 
@@ -377,6 +378,7 @@
 	struct atmarp_entry *entry;
 	struct atm_vcc *vcc;
 	int old;
+	unsigned long flags;
 
 	DPRINTK("clip_start_xmit (skb %p)\n",skb);
 	if (!skb->dst) {
@@ -439,7 +441,7 @@
 		return 0;
 	}
 	if (old) return 0;
-	spin_lock(&clip_priv->xoff_lock);
+	spin_lock_irqsave(&clip_priv->xoff_lock,flags);
 	netif_stop_queue(dev); /* XOFF -> throttle immediately */
 	barrier();
 	if (!entry->vccs->xoff)
@@ -448,7 +450,7 @@
 		   good enough, because nothing should really be asleep because
 		   of the brief netif_stop_queue. If this isn't true or if it
 		   changes, use netif_wake_queue instead. */
-	spin_unlock(&clip_priv->xoff_lock);
+	spin_unlock_irqrestore(&clip_priv->xoff_lock,flags);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/common.c linux/net/atm/common.c
--- v2.3.99-pre5/linux/net/atm/common.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/common.c	Fri Apr 14 09:37:20 2000
@@ -114,7 +114,6 @@
 	vcc->atm_options = vcc->aal_options = 0;
 	vcc->timestamp.tv_sec = vcc->timestamp.tv_usec = 0;
 	init_waitqueue_head(&vcc->sleep);
-	init_waitqueue_head(&vcc->wsleep);
 	skb_queue_head_init(&vcc->recvq);
 	skb_queue_head_init(&vcc->listenq);
 	sock->sk = sk;
@@ -412,7 +411,7 @@
 	if (!size) return 0;
 	/* verify_area is done by net/socket.c */
 	eff = (size+3) & ~3; /* align to word boundary */
-	add_wait_queue(&vcc->wsleep,&wait);
+	add_wait_queue(&vcc->sleep,&wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	error = 0;
 	while (!(skb = vcc->alloc_tx(vcc,eff))) {
@@ -437,7 +436,7 @@
 		}
 	}
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&vcc->wsleep,&wait);
+	remove_wait_queue(&vcc->sleep,&wait);
 	if (error) return error;
 	skb->dev = NULL; /* for paths shared with net_device interfaces */
 	ATM_SKB(skb)->iovcnt = 0;
@@ -459,7 +458,6 @@
 
 	vcc = ATM_SD(sock);
 	poll_wait(file,&vcc->sleep,wait);
-	poll_wait(file,&vcc->wsleep,wait);
 	mask = 0;
 	if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq))
 		mask |= POLLIN | POLLRDNORM;
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/common.h linux/net/atm/common.h
--- v2.3.99-pre5/linux/net/atm/common.h	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/common.h	Fri Apr 14 09:37:20 2000
@@ -1,6 +1,6 @@
 /* net/atm/common.h - ATM sockets (common part for PVC and SVC) */
  
-/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
 
 
 #ifndef NET_ATM_COMMON_H
@@ -27,9 +27,6 @@
 int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci);
 void atm_release_vcc_sk(struct sock *sk,int free_sk);
 int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos);
-/* -- now in atmdev.h:
-void atm_async_release_vcc(struct atm_vcc *vcc,int reply);
-*/
 void atm_shutdown_dev(struct atm_dev *dev);
 
 int atm_proc_init(void);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/lane_mpoa_init.c linux/net/atm/lane_mpoa_init.c
--- v2.3.99-pre5/linux/net/atm/lane_mpoa_init.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/lane_mpoa_init.c	Fri Apr 14 09:37:20 2000
@@ -38,12 +38,10 @@
 
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-rwlock_t lane_bridge_hook_lock = RW_LOCK_UNLOCKED;
 struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
 						unsigned char *addr) = NULL;
 void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) = NULL;
 #if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE)
-EXPORT_SYMBOL(lane_bridge_hook_lock);
 EXPORT_SYMBOL(br_fdb_get_hook);
 EXPORT_SYMBOL(br_fdb_put_hook);
 #endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/lec.c linux/net/atm/lec.c
--- v2.3.99-pre5/linux/net/atm/lec.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/lec.c	Fri Apr 14 09:37:20 2000
@@ -34,7 +34,7 @@
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 #include <linux/if_bridge.h>
 #include "../bridge/br_private.h"
-unsigned char bridge_ula[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
+static unsigned char bridge_ula[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
 #endif
 
 /* Modular too */
@@ -472,11 +472,8 @@
                         mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3],
                         mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]);
 
-                read_lock(&lane_bridge_hook_lock);
-                if (br_fdb_get_hook == NULL || dev->br_port == NULL) {
-                        read_unlock(&lane_bridge_hook_lock);
+                if (br_fdb_get_hook == NULL || dev->br_port == NULL)
                         break;
-                }
 
                 f = br_fdb_get_hook(dev->br_port->br, mesg->content.proxy.mac_addr);
                 if (f != NULL &&
@@ -489,7 +486,6 @@
                         skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
                         if (skb2 == NULL) {
                                 br_fdb_put_hook(f);
-                                read_unlock(&lane_bridge_hook_lock);
                                 break;
                         }
                         skb2->len = sizeof(struct atmlec_msg);
@@ -499,7 +495,6 @@
                         wake_up(&priv->lecd->sleep);
                 }
                 if (f != NULL) br_fdb_put_hook(f);
-                read_unlock(&lane_bridge_hook_lock);
 #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
                 }
                 break;
@@ -696,7 +691,6 @@
                         lec_arp_check_empties(priv, vcc, skb);
                 }
                 skb->dev = dev;
-		skb->rx_dev = NULL;
                 skb->data += 2; /* skip lec_id */
 #ifdef CONFIG_TR
                 if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
@@ -1079,8 +1073,8 @@
         if (entry->recv_vcc) {
                 entry->recv_vcc->push = entry->old_recv_push;
 #if 0
-                set_bit(ATM_VF_RELEASED,&entry->vcc->flags);
-		clear_bit(ATM_VF_READY,&entry->vcc->flags);
+                set_bit(ATM_VF_RELEASED,&entry->recv_vcc->flags);
+		clear_bit(ATM_VF_READY,&entry->recv_vcc->flags);
                 entry->recv_vcc->push(entry->recv_vcc, NULL);
 #endif
 		atm_async_release_vcc(entry->recv_vcc, -EPIPE);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/lec.h linux/net/atm/lec.h
--- v2.3.99-pre5/linux/net/atm/lec.h	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/lec.h	Fri Apr 14 09:37:20 2000
@@ -16,7 +16,6 @@
 
 #if defined (CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 #include <linux/if_bridge.h>
-extern rwlock_t lane_bridge_hook_lock;
 struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
                                                 unsigned char *addr);
 void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/mpc.c linux/net/atm/mpc.c
--- v2.3.99-pre5/linux/net/atm/mpc.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/mpc.c	Fri Apr 14 09:43:49 2000
@@ -62,7 +62,7 @@
 static void set_mps_mac_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc);
 
 static uint8_t *copy_macs(struct mpoa_client *mpc, uint8_t *router_mac,
-                          uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type);
+			  uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type);
 static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry);
 
 static void send_set_mps_ctrl_addr(char *addr, struct mpoa_client *mpc);
@@ -76,25 +76,25 @@
 static void mpc_cache_check( unsigned long checking_time  );
 
 static struct llc_snap_hdr llc_snap_mpoa_ctrl = {
-        0xaa, 0xaa, 0x03,
-        {0x00, 0x00, 0x5e},
-        {0x00, 0x03}         /* For MPOA control PDUs */
+	0xaa, 0xaa, 0x03,
+	{0x00, 0x00, 0x5e},
+	{0x00, 0x03}         /* For MPOA control PDUs */
 };        
 static struct llc_snap_hdr llc_snap_mpoa_data = {
-        0xaa, 0xaa, 0x03,
-        {0x00, 0x00, 0x00},
-        {0x08, 0x00}         /* This is for IP PDUs only */
+	0xaa, 0xaa, 0x03,
+	{0x00, 0x00, 0x00},
+	{0x08, 0x00}         /* This is for IP PDUs only */
 };        
 static struct llc_snap_hdr llc_snap_mpoa_data_tagged = {
-        0xaa, 0xaa, 0x03,
-        {0x00, 0x00, 0x00},
-        {0x88, 0x4c}         /* This is for tagged data PDUs */
+	0xaa, 0xaa, 0x03,
+	{0x00, 0x00, 0x00},
+	{0x88, 0x4c}         /* This is for tagged data PDUs */
 };        
 
 static struct notifier_block mpoa_notifier = {
-        mpoa_event_listener,
-        NULL,
-        0
+	mpoa_event_listener,
+	NULL,
+	0
 };
 
 #ifdef CONFIG_PROC_FS
@@ -109,44 +109,44 @@
 
 static struct mpoa_client *find_mpc_by_itfnum(int itf)
 {
-        struct mpoa_client *mpc;
-        
-        mpc = mpcs;  /* our global linked list */
-        while (mpc != NULL) {
-                if (mpc->dev_num == itf)
-                        return mpc;
-                mpc = mpc->next;    
-        }
+	struct mpoa_client *mpc;
+	
+	mpc = mpcs;  /* our global linked list */
+	while (mpc != NULL) {
+		if (mpc->dev_num == itf)
+			return mpc;
+		mpc = mpc->next;    
+	}
 
-        return NULL;   /* not found */
+	return NULL;   /* not found */
 }
 
 static struct mpoa_client *find_mpc_by_vcc(struct atm_vcc *vcc)
 {
-        struct mpoa_client *mpc;
-        
-        mpc = mpcs;  /* our global linked list */
-        while (mpc != NULL) {
-                if (mpc->mpoad_vcc == vcc)
-                        return mpc;
-                mpc = mpc->next;
-        }
+	struct mpoa_client *mpc;
+	
+	mpc = mpcs;  /* our global linked list */
+	while (mpc != NULL) {
+		if (mpc->mpoad_vcc == vcc)
+			return mpc;
+		mpc = mpc->next;
+	}
 
-        return NULL;   /* not found */
+	return NULL;   /* not found */
 }
 
 static struct mpoa_client *find_mpc_by_lec(struct net_device *dev)
 {
-        struct mpoa_client *mpc;
-        
-        mpc = mpcs;  /* our global linked list */
-        while (mpc != NULL) {
-                if (mpc->dev == dev)
-                        return mpc;
-                mpc = mpc->next;
-        }
+	struct mpoa_client *mpc;
+	
+	mpc = mpcs;  /* our global linked list */
+	while (mpc != NULL) {
+		if (mpc->dev == dev)
+			return mpc;
+		mpc = mpc->next;
+	}
 
-        return NULL;   /* not found */
+	return NULL;   /* not found */
 }
 
 /*
@@ -158,42 +158,42 @@
  */
 struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos)
 {
-        struct atm_mpoa_qos *entry;
+	struct atm_mpoa_qos *entry;
 
-        entry = atm_mpoa_search_qos(dst_ip);
-        if (entry != NULL) {
-                entry->qos = *qos;
-                return entry;
-        }
-
-        entry = kmalloc(sizeof(struct atm_qos), GFP_KERNEL);
-        if (entry == NULL) {
-                printk("mpoa: atm_mpoa_add_qos: out of memory\n");
-                return entry;
-        }
+	entry = atm_mpoa_search_qos(dst_ip);
+	if (entry != NULL) {
+		entry->qos = *qos;
+		return entry;
+	}
 
-        entry->ipaddr = dst_ip;
-        entry->qos = *qos;
+	entry = kmalloc(sizeof(struct atm_qos), GFP_KERNEL);
+	if (entry == NULL) {
+		printk("mpoa: atm_mpoa_add_qos: out of memory\n");
+		return entry;
+	}
 
-        entry->next = qos_head;
-        qos_head = entry;
+	entry->ipaddr = dst_ip;
+	entry->qos = *qos;
 
-        return entry;
+	entry->next = qos_head;
+	qos_head = entry;
+
+	return entry;
 }
 
 struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip)
 {
-        struct atm_mpoa_qos *qos;
+	struct atm_mpoa_qos *qos;
 
-        qos = qos_head;
-        while( qos != NULL ){
-                if(qos->ipaddr == dst_ip) {
-                        break;
+	qos = qos_head;
+	while( qos != NULL ){
+		if(qos->ipaddr == dst_ip) {
+			break;
 		}
-                qos = qos->next;
-        }
+		qos = qos->next;
+	}
 
-        return qos;
+	return qos;
 }        
 
 /*
@@ -202,26 +202,26 @@
 int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry)
 {
 
-        struct atm_mpoa_qos *curr;
+	struct atm_mpoa_qos *curr;
 
-        if (entry == NULL) return 0;
-        if (entry == qos_head) {
-                qos_head = qos_head->next;
-                kfree(entry);
-                return 1;
-        }
-
-        curr = qos_head;
-        while (curr != NULL) {
-                if (curr->next == entry) {
-                        curr->next = entry->next;
-                        kfree(entry);
-                        return 1;
-                }
-                curr = curr->next;
-        }
+	if (entry == NULL) return 0;
+	if (entry == qos_head) {
+		qos_head = qos_head->next;
+		kfree(entry);
+		return 1;
+	}
 
-        return 0;
+	curr = qos_head;
+	while (curr != NULL) {
+		if (curr->next == entry) {
+			curr->next = entry->next;
+			kfree(entry);
+			return 1;
+		}
+		curr = curr->next;
+	}
+
+	return 0;
 }
 
 void atm_mpoa_disp_qos(char *page, int *len)
@@ -238,9 +238,9 @@
 	ipaddr[sizeof(ipaddr)-1] = '\0';
 	while (qos != NULL) {
 		ip = (unsigned char *)&qos->ipaddr;
-		sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
-		*len += sprintf(page + *len, "%-16s\n     %-7d %-7d %-7d %-7d %-7d\n     %-7d %-7d %-7d %-7d %-7d\n",
-				ipaddr,
+		sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(ip));
+		*len += sprintf(page + *len, "%%u.%u.%u.%u\n     %-7d %-7d %-7d %-7d %-7d\n     %-7d %-7d %-7d %-7d %-7d\n",
+				NIPQUAD(ipaddr),
 				qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu,
 				qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu);
 		qos = qos->next;
@@ -251,28 +251,26 @@
 
 static struct net_device *find_lec_by_itfnum(int itf)
 {
-        extern struct atm_lane_ops atm_lane_ops; /* in common.c */
-        
-        if (atm_lane_ops.get_lecs == NULL)
-                return NULL;
+	extern struct atm_lane_ops atm_lane_ops; /* in common.c */
+	
+	if (atm_lane_ops.get_lecs == NULL)
+		return NULL;
 
-        return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */
+	return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */
 }
 
 static struct mpoa_client *alloc_mpc(void)
 {
-        struct mpoa_client *mpc;
+	struct mpoa_client *mpc;
 
-        mpc = kmalloc(sizeof (struct mpoa_client), GFP_KERNEL);
-        if (mpc == NULL)
-                return NULL;
-        memset(mpc, 0, sizeof(struct mpoa_client));
-#if 0 /* compiler seems to barf on this */
-        mpc->ingress_lock = RW_LOCK_UNLOCKED;
-        mpc->egress_lock  = RW_LOCK_UNLOCKED;
-#endif
-        mpc->next = mpcs;
-        atm_mpoa_init_cache(mpc);
+	mpc = kmalloc(sizeof (struct mpoa_client), GFP_KERNEL);
+	if (mpc == NULL)
+		return NULL;
+	memset(mpc, 0, sizeof(struct mpoa_client));
+	mpc->ingress_lock = RW_LOCK_UNLOCKED;
+	mpc->egress_lock  = RW_LOCK_UNLOCKED;
+	mpc->next = mpcs;
+	atm_mpoa_init_cache(mpc);
 
 	mpc->parameters.mpc_p1 = MPC_P1;
 	mpc->parameters.mpc_p2 = MPC_P2;
@@ -281,9 +279,9 @@
 	mpc->parameters.mpc_p5 = MPC_P5; 
 	mpc->parameters.mpc_p6 = MPC_P6;
 	
-        mpcs = mpc;
+	mpcs = mpc;
 	
-        return mpc;
+	return mpc;
 }
 
 /*
@@ -295,58 +293,58 @@
  */
 static void start_mpc(struct mpoa_client *mpc, struct net_device *dev)
 {
-        
-        dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name); 
-        if (dev->hard_start_xmit == NULL) {
-                printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n",
-                       dev->name);
-                return;
-        }
-        mpc->old_hard_start_xmit = dev->hard_start_xmit;
-        dev->hard_start_xmit = mpc_send_packet;
+	
+	dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name); 
+	if (dev->hard_start_xmit == NULL) {
+		printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n",
+		       dev->name);
+		return;
+	}
+	mpc->old_hard_start_xmit = dev->hard_start_xmit;
+	dev->hard_start_xmit = mpc_send_packet;
 
-        return;
+	return;
 }
 
 static void stop_mpc(struct mpoa_client *mpc)
 {
-        
-        dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name); 
+	
+	dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name); 
 
-        /* Lets not nullify lec device's dev->hard_start_xmit */
-        if (mpc->dev->hard_start_xmit != mpc_send_packet) {
-                dprintk(" mpc already stopped, not fatal\n");
-                return;
-        }
-        dprintk("\n");
-        mpc->dev->hard_start_xmit = mpc->old_hard_start_xmit;
-        mpc->old_hard_start_xmit = NULL;
+	/* Lets not nullify lec device's dev->hard_start_xmit */
+	if (mpc->dev->hard_start_xmit != mpc_send_packet) {
+		dprintk(" mpc already stopped, not fatal\n");
+		return;
+	}
+	dprintk("\n");
+	mpc->dev->hard_start_xmit = mpc->old_hard_start_xmit;
+	mpc->old_hard_start_xmit = NULL;
 	/* close_shortcuts(mpc);    ??? FIXME */
-        
-        return;
+	
+	return;
 }
 
 static const char * __attribute__ ((unused)) mpoa_device_type_string(char type)
 {
-        switch(type) {
-        case NON_MPOA:
-                return "non-MPOA device";
-                break;
-        case MPS:
-                return "MPS";
-                break;
-        case MPC:
-                return "MPC";
-                break;
-        case MPS_AND_MPC:
-                return "both MPS and MPC";
-                break;
-        default:
-                return "unspecified (non-MPOA) device";
-                break;
-        }
+	switch(type) {
+	case NON_MPOA:
+		return "non-MPOA device";
+		break;
+	case MPS:
+		return "MPS";
+		break;
+	case MPC:
+		return "MPC";
+		break;
+	case MPS_AND_MPC:
+		return "both MPS and MPC";
+		break;
+	default:
+		return "unspecified (non-MPOA) device";
+		break;
+	}
 
-        return ""; /* not reached */
+	return ""; /* not reached */
 }
 
 /*
@@ -363,77 +361,77 @@
  *
  */
 static void lane2_assoc_ind(struct net_device *dev, uint8_t *mac_addr,
-                            uint8_t *tlvs, uint32_t sizeoftlvs)
+			    uint8_t *tlvs, uint32_t sizeoftlvs)
 {
-        uint32_t type;
-        uint8_t length, mpoa_device_type, number_of_mps_macs;
-        uint8_t *end_of_tlvs;
-        struct mpoa_client *mpc;
-        
-        mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */
-        dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name);
-        dprintk("total length of all TLVs %d\n", sizeoftlvs);
+	uint32_t type;
+	uint8_t length, mpoa_device_type, number_of_mps_macs;
+	uint8_t *end_of_tlvs;
+	struct mpoa_client *mpc;
+	
+	mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */
+	dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name);
+	dprintk("total length of all TLVs %d\n", sizeoftlvs);
 	mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */
-        if (mpc == NULL) {
-                printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev->name);
-                return;
-        }
-        end_of_tlvs = tlvs + sizeoftlvs;
-        while (end_of_tlvs - tlvs >= 5) {
-                type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3];
-                length = tlvs[4];
-                tlvs += 5;
-                dprintk("    type 0x%x length %02x\n", type, length);
-                if (tlvs + length > end_of_tlvs) {
-                        printk("TLV value extends past its buffer, aborting parse\n");
-                        return;
-                }
-                
-                if (type == 0) {
-                        printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name);
-                        return;
+	if (mpc == NULL) {
+		printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev->name);
+		return;
+	}
+	end_of_tlvs = tlvs + sizeoftlvs;
+	while (end_of_tlvs - tlvs >= 5) {
+		type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3];
+		length = tlvs[4];
+		tlvs += 5;
+		dprintk("    type 0x%x length %02x\n", type, length);
+		if (tlvs + length > end_of_tlvs) {
+			printk("TLV value extends past its buffer, aborting parse\n");
+			return;
+		}
+		
+		if (type == 0) {
+			printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name);
+			return;
 		}
 
-                if (type != TLV_MPOA_DEVICE_TYPE) {
-                        tlvs += length;
-                        continue;  /* skip other TLVs */
-                }
-                mpoa_device_type = *tlvs++;
-                number_of_mps_macs = *tlvs++;
-                dprintk("mpoa: (%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type));
-                if (mpoa_device_type == MPS_AND_MPC &&
-                    length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */
-                        printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
-                               dev->name);
-                        continue;
-                }
-                if ((mpoa_device_type == MPS || mpoa_device_type == MPC)
-                    && length < 22 + number_of_mps_macs*ETH_ALEN) {
-                        printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
-                                dev->name);
-                        continue;
-                }
-                if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) {
-                        dprintk("ignoring non-MPS device\n");
-                        if (mpoa_device_type == MPC) tlvs += 20;
-                        continue;  /* we are only interested in MPSs */
-                }
-                if (number_of_mps_macs == 0 && mpoa_device_type == MPS_AND_MPC) {
-                        printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev->name);
-                        continue;  /* someone should read the spec */
-                }
-                dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs);
-                
-                /* ok, now we can go and tell our daemon the control address of MPS */
-                send_set_mps_ctrl_addr(tlvs, mpc);
-                
-                tlvs = copy_macs(mpc, mac_addr, tlvs, number_of_mps_macs, mpoa_device_type);
-                if (tlvs == NULL) return;
-        }
-        if (end_of_tlvs - tlvs != 0)
-                printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n",
-                       dev->name, end_of_tlvs - tlvs);
-        return;
+		if (type != TLV_MPOA_DEVICE_TYPE) {
+			tlvs += length;
+			continue;  /* skip other TLVs */
+		}
+		mpoa_device_type = *tlvs++;
+		number_of_mps_macs = *tlvs++;
+		dprintk("mpoa: (%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type));
+		if (mpoa_device_type == MPS_AND_MPC &&
+		    length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */
+			printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
+			       dev->name);
+			continue;
+		}
+		if ((mpoa_device_type == MPS || mpoa_device_type == MPC)
+		    && length < 22 + number_of_mps_macs*ETH_ALEN) {
+			printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
+				dev->name);
+			continue;
+		}
+		if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) {
+			dprintk("ignoring non-MPS device\n");
+			if (mpoa_device_type == MPC) tlvs += 20;
+			continue;  /* we are only interested in MPSs */
+		}
+		if (number_of_mps_macs == 0 && mpoa_device_type == MPS_AND_MPC) {
+			printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev->name);
+			continue;  /* someone should read the spec */
+		}
+		dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs);
+		
+		/* ok, now we can go and tell our daemon the control address of MPS */
+		send_set_mps_ctrl_addr(tlvs, mpc);
+		
+		tlvs = copy_macs(mpc, mac_addr, tlvs, number_of_mps_macs, mpoa_device_type);
+		if (tlvs == NULL) return;
+	}
+	if (end_of_tlvs - tlvs != 0)
+		printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n",
+		       dev->name, end_of_tlvs - tlvs);
+	return;
 }
 
 /*
@@ -442,91 +440,94 @@
  * For a freshly allocated MPOA client mpc->mps_macs == 0.
  */
 static uint8_t *copy_macs(struct mpoa_client *mpc, uint8_t *router_mac,
-                          uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type)
+			  uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type)
 {
-        int num_macs;
-        num_macs = (mps_macs > 1) ? mps_macs : 1;
+	int num_macs;
+	num_macs = (mps_macs > 1) ? mps_macs : 1;
 
-        if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */
-                if (mpc->number_of_mps_macs != 0) kfree(mpc->mps_macs);
-                mpc->number_of_mps_macs = 0;
-                mpc->mps_macs = kmalloc(num_macs*ETH_ALEN, GFP_KERNEL);
-                if (mpc->mps_macs == NULL) {
-                        printk("mpoa: (%s) copy_macs: out of mem\n", mpc->dev->name);
-                        return NULL;
-                }
-        }
-        memcpy(mpc->mps_macs, router_mac, ETH_ALEN);
-        tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20;
-        if (mps_macs > 0)
-                memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN);
-        tlvs += mps_macs*ETH_ALEN;
-        mpc->number_of_mps_macs = num_macs;
+	if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */
+		if (mpc->number_of_mps_macs != 0) kfree(mpc->mps_macs);
+		mpc->number_of_mps_macs = 0;
+		mpc->mps_macs = kmalloc(num_macs*ETH_ALEN, GFP_KERNEL);
+		if (mpc->mps_macs == NULL) {
+			printk("mpoa: (%s) copy_macs: out of mem\n", mpc->dev->name);
+			return NULL;
+		}
+	}
+	memcpy(mpc->mps_macs, router_mac, ETH_ALEN);
+	tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20;
+	if (mps_macs > 0)
+		memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN);
+	tlvs += mps_macs*ETH_ALEN;
+	mpc->number_of_mps_macs = num_macs;
 
-        return tlvs;
+	return tlvs;
 }
 
-/* FIXME: tarvitsee työtä */
 static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
 {
-        in_cache_entry *entry;
-        struct iphdr *iph;
-        char *buff;
-        uint32_t ipaddr = 0;
-
-        static struct {
-                struct llc_snap_hdr hdr;
-                uint32_t tag;
-        } tagged_llc_snap_hdr = {
-                {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}},
-                0
-        };
+	in_cache_entry *entry;
+	struct iphdr *iph;
+	char *buff;
+	uint32_t ipaddr = 0;
+
+	static struct {
+		struct llc_snap_hdr hdr;
+		uint32_t tag;
+	} tagged_llc_snap_hdr = {
+		{0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}},
+		0
+	};
 
-        buff = skb->data + mpc->dev->hard_header_len;
-        iph = (struct iphdr *)buff;
+	buff = skb->data + mpc->dev->hard_header_len;
+	iph = (struct iphdr *)buff;
 	ipaddr = iph->daddr;
 
-        ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr);        
+	ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr);        
+
+	entry = mpc->in_ops->get(ipaddr, mpc);
+	if (entry == NULL) {
+		entry = mpc->in_ops->add_entry(ipaddr, mpc);
+		if (entry != NULL) mpc->in_ops->put(entry);
+		return 1;
+	}
+	if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){   /* threshold not exceeded or VCC not ready */
+		ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name);        
+		mpc->in_ops->put(entry);
+		return 1;
+	}
 
-        entry = mpc->in_ops->search(ipaddr, mpc);
-        if (entry == NULL) {
-                mpc->in_ops->new_entry(ipaddr, mpc);
-                return 1;
-        }
-        if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){   /* threshold not exceeded or VCC not ready */
-                ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name);        
-                return 1;
-        }
-
-        ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name);        
-        /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */
-        if (iph->ttl <= 1) {
-              ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl);        
-              return 1;
-        }
-        iph->ttl--;
-        iph->check = 0;
-        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
-        if (entry->ctrl_info.tag != 0) {
-                ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag);
-                tagged_llc_snap_hdr.tag = entry->ctrl_info.tag;
-                skb_pull(skb, ETH_HLEN);                       /* get rid of Eth header */
-                skb_push(skb, sizeof(tagged_llc_snap_hdr));    /* add LLC/SNAP header   */
-                memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr));
-        } else {
-                skb_pull(skb, ETH_HLEN);                        /* get rid of Eth header */
-                skb_push(skb, sizeof(struct llc_snap_hdr));     /* add LLC/SNAP header + tag  */
-                memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr));
-        }
+	ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name);        
+	/* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */
+	if (iph->ttl <= 1) {
+		ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl);        
+		mpc->in_ops->put(entry);
+		return 1;
+	}
+	iph->ttl--;
+	iph->check = 0;
+	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+	if (entry->ctrl_info.tag != 0) {
+		ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag);
+		tagged_llc_snap_hdr.tag = entry->ctrl_info.tag;
+		skb_pull(skb, ETH_HLEN);                       /* get rid of Eth header */
+		skb_push(skb, sizeof(tagged_llc_snap_hdr));    /* add LLC/SNAP header   */
+		memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr));
+	} else {
+		skb_pull(skb, ETH_HLEN);                        /* get rid of Eth header */
+		skb_push(skb, sizeof(struct llc_snap_hdr));     /* add LLC/SNAP header + tag  */
+		memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr));
+	}
 
-        atomic_add(skb->truesize, &entry->shortcut->tx_inuse);
+	atomic_add(skb->truesize, &entry->shortcut->tx_inuse);
 	ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */
 	ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
-        entry->shortcut->send(entry->shortcut, skb);
+	entry->shortcut->send(entry->shortcut, skb);
 	entry->packets_fwded++;
+	mpc->in_ops->put(entry);
 
-        return 0;
+	return 0;
 }
 
 /*
@@ -534,75 +535,77 @@
  */
 static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-        int retval;
-        struct mpoa_client *mpc;
-        struct ethhdr *eth;
-        int i = 0;
-        
-        mpc = find_mpc_by_lec(dev); /* this should NEVER fail */
-        if(mpc == NULL) {
-	        printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev->name);
-                goto non_ip;
-	}
-
-        eth = (struct ethhdr *)skb->data;
-        if (eth->h_proto != htons(ETH_P_IP))
-                goto non_ip; /* Multi-Protocol Over ATM :-) */
-
-        while (i < mpc->number_of_mps_macs) {
-                if (memcmp(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN), ETH_ALEN) == 0)
-                        if ( send_via_shortcut(skb, mpc) == 0 )           /* try shortcut */
-                                return 0;                                 /* success!     */
-                i++;
-        }
+	int retval;
+	struct mpoa_client *mpc;
+	struct ethhdr *eth;
+	int i = 0;
+	
+	mpc = find_mpc_by_lec(dev); /* this should NEVER fail */
+	if(mpc == NULL) {
+		printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev->name);
+		goto non_ip;
+	}
+
+	eth = (struct ethhdr *)skb->data;
+	if (eth->h_proto != htons(ETH_P_IP))
+		goto non_ip; /* Multi-Protocol Over ATM :-) */
+
+	while (i < mpc->number_of_mps_macs) {
+		if (memcmp(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN), ETH_ALEN) == 0)
+			if ( send_via_shortcut(skb, mpc) == 0 )           /* try shortcut */
+				return 0;                                 /* success!     */
+		i++;
+	}
 
  non_ip:
-        retval = mpc->old_hard_start_xmit(skb,dev);
-        
-        return retval;
+	retval = mpc->old_hard_start_xmit(skb,dev);
+	
+	return retval;
 }
 
 int atm_mpoa_vcc_attach(struct atm_vcc *vcc, long arg)
 {
-        int bytes_left;
-        struct mpoa_client *mpc;
-        struct atmmpc_ioc ioc_data;
-        in_cache_entry *in_entry;
-        uint32_t  ipaddr;
+	int bytes_left;
+	struct mpoa_client *mpc;
+	struct atmmpc_ioc ioc_data;
+	in_cache_entry *in_entry;
+	uint32_t  ipaddr;
 	unsigned char *ip;
 
-        bytes_left = copy_from_user(&ioc_data, (void *)arg, sizeof(struct atmmpc_ioc));
-        if (bytes_left != 0) {
-                printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left);
-                return -EFAULT;
-        }
-        ipaddr = ioc_data.ipaddr;
-        if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF)
-                return -EINVAL;
-        
-        mpc = find_mpc_by_itfnum(ioc_data.dev_num);
-        if (mpc == NULL)
-                return -EINVAL;
-        
-        if (ioc_data.type == MPC_SOCKET_INGRESS) {
-                in_entry = mpc->in_ops->search(ipaddr, mpc);
-                if (in_entry == NULL || in_entry->entry_state < INGRESS_RESOLVED) {
-                        printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n",
-                                mpc->dev->name);
-                        return -EINVAL;
-                }
+	bytes_left = copy_from_user(&ioc_data, (void *)arg, sizeof(struct atmmpc_ioc));
+	if (bytes_left != 0) {
+		printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left);
+		return -EFAULT;
+	}
+	ipaddr = ioc_data.ipaddr;
+	if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF)
+		return -EINVAL;
+	
+	mpc = find_mpc_by_itfnum(ioc_data.dev_num);
+	if (mpc == NULL)
+		return -EINVAL;
+	
+	if (ioc_data.type == MPC_SOCKET_INGRESS) {
+		in_entry = mpc->in_ops->get(ipaddr, mpc);
+		if (in_entry == NULL || in_entry->entry_state < INGRESS_RESOLVED) {
+			printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n",
+				mpc->dev->name);
+			if (in_entry != NULL) mpc->in_ops->put(in_entry);
+			return -EINVAL;
+		}
 		ip = (unsigned char*)&in_entry->ctrl_info.in_dst_ip;
-                printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n",
-                       mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
-                in_entry->shortcut = vcc;
-        } else {
-                printk("mpoa: (%s) mpc_vcc_attach: attaching egress SVC\n", mpc->dev->name);
-        }
-        
-        vcc->proto_data = mpc->dev;
-        vcc->push = mpc_push;
+		printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n",
+		       mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+		in_entry->shortcut = vcc;
+		mpc->in_ops->put(in_entry);
+	} else {
+		printk("mpoa: (%s) mpc_vcc_attach: attaching egress SVC\n", mpc->dev->name);
+	}
 
-        return 0;
+	vcc->proto_data = mpc->dev;
+	vcc->push = mpc_push;
+
+	return 0;
 }
 
 /*
@@ -610,251 +613,250 @@
  */
 static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev)
 {
-        struct mpoa_client *mpc;
-        in_cache_entry *in_entry;
-        eg_cache_entry *eg_entry;
-        
-        mpc = find_mpc_by_lec(dev);
-        if (mpc == NULL) {
-                printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev->name);
-                return;
-        }
-
-        dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name);
-        in_entry = mpc->in_ops->search_by_vcc(vcc, mpc);
-        if (in_entry) {
-                unsigned char *ip __attribute__ ((unused)) =
+	struct mpoa_client *mpc;
+	in_cache_entry *in_entry;
+	eg_cache_entry *eg_entry;
+	
+	mpc = find_mpc_by_lec(dev);
+	if (mpc == NULL) {
+		printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev->name);
+		return;
+	}
+
+	dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name);
+	in_entry = mpc->in_ops->get_by_vcc(vcc, mpc);
+	if (in_entry) {
+		unsigned char *ip __attribute__ ((unused)) =
 		    (unsigned char *)&in_entry->ctrl_info.in_dst_ip;
-	        dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n",
-                       mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
-                in_entry->shortcut = NULL;
-        }
-        eg_entry = mpc->eg_ops->search_by_vcc(vcc, mpc);
-        if (eg_entry) {
-	        dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", mpc->dev->name);
-                eg_entry->shortcut = NULL;
-        }
+		dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n",
+		       mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+		in_entry->shortcut = NULL;
+		mpc->in_ops->put(in_entry);
+	}
+	eg_entry = mpc->eg_ops->get_by_vcc(vcc, mpc);
+	if (eg_entry) {
+		dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", mpc->dev->name);
+		eg_entry->shortcut = NULL;
+		mpc->eg_ops->put(eg_entry);
+	}
 
-        if (in_entry == NULL && eg_entry == NULL)
-                dprintk("mpoa: (%s) mpc_vcc_close:  unused vcc closed\n", dev->name);
+	if (in_entry == NULL && eg_entry == NULL)
+		dprintk("mpoa: (%s) mpc_vcc_close:  unused vcc closed\n", dev->name);
 
-        return;
+	return;
 }
 
 static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
 {
-        struct net_device *dev = (struct net_device *)vcc->proto_data;
-        struct sk_buff *new_skb;
-        eg_cache_entry *eg;
-        struct mpoa_client *mpc;
+	struct net_device *dev = (struct net_device *)vcc->proto_data;
+	struct sk_buff *new_skb;
+	eg_cache_entry *eg;
+	struct mpoa_client *mpc;
 	uint32_t tag;
-        char *tmp;
-        
-        ddprintk("mpoa: (%s) mpc_push:\n", dev->name);
-        if (skb == NULL) {
-                dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name);
-                mpc_vcc_close(vcc, dev);
-                return;
-        }
-        
-        skb->dev = dev;
-        if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) {
-                dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name);
-                skb_queue_tail(&vcc->recvq, skb);           /* Pass control packets to daemon */
-                wake_up(&vcc->sleep);
-                return;
-        }
+	char *tmp;
+	
+	ddprintk("mpoa: (%s) mpc_push:\n", dev->name);
+	if (skb == NULL) {
+		dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name);
+		mpc_vcc_close(vcc, dev);
+		return;
+	}
+	
+	skb->dev = dev;
+	if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) {
+		dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name);
+		skb_queue_tail(&vcc->recvq, skb);           /* Pass control packets to daemon */
+		wake_up(&vcc->sleep);
+		return;
+	}
 
-        /* data coming over the shortcut */
-        atm_return(vcc, skb->truesize);
+	/* data coming over the shortcut */
+	atm_return(vcc, skb->truesize);
 
 	mpc = find_mpc_by_lec(dev);
-        if (mpc == NULL) {
-                printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name);
-                return;
-        }
-
-        if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */
-                ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name);
-
-        } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */
-                printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name);
-                printk("           mpc_push: non-tagged data unsupported, purging\n");
-		kfree_skb(skb);
-                return;
-        } else {
-                printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name);
-		kfree_skb(skb);
-                return;
-        }
+	if (mpc == NULL) {
+		printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name);
+		return;
+	}
 
-        tmp = skb->data + sizeof(struct llc_snap_hdr);
-        tag = *(uint32_t *)tmp;
+	if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */
+		ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name);
 
-        eg = mpc->eg_ops->search_by_tag(tag, mpc);
-        if (eg == NULL) {
-                printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n",
-                       dev->name,tag);
-                purge_egress_shortcut(vcc, NULL);
-                kfree_skb(skb);
-                return;
-        }
-        
-        /*
-         * See if ingress MPC is using shortcut we opened as a return channel.
-         * This means we have a bi-directional vcc opened by us.
-         */ 
-        if (eg->shortcut == NULL) {
-                eg->shortcut = vcc;
-                printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name);
-        }
-
-        skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */
-        new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */
-        kfree_skb(skb);
-        if (new_skb == NULL) return;
-        skb_push(new_skb, eg->ctrl_info.DH_length);     /* add MAC header */
-        memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length);
-        new_skb->protocol = eth_type_trans(new_skb, dev);
-        new_skb->nh.raw = new_skb->data;
+	} else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */
+		printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name);
+		printk("           mpc_push: non-tagged data unsupported, purging\n");
+		dev_kfree_skb_any(skb);
+		return;
+	} else {
+		printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name);
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	tmp = skb->data + sizeof(struct llc_snap_hdr);
+	tag = *(uint32_t *)tmp;
+
+	eg = mpc->eg_ops->get_by_tag(tag, mpc);
+	if (eg == NULL) {
+		printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n",
+		       dev->name,tag);
+		purge_egress_shortcut(vcc, NULL);
+		dev_kfree_skb_any(skb);
+		return;
+	}
+	
+	/*
+	 * See if ingress MPC is using shortcut we opened as a return channel.
+	 * This means we have a bi-directional vcc opened by us.
+	 */ 
+	if (eg->shortcut == NULL) {
+		eg->shortcut = vcc;
+		printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name);
+	}
+
+	skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */
+	new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */
+	dev_kfree_skb_any(skb);
+	if (new_skb == NULL){
+		mpc->eg_ops->put(eg);
+		return;
+	}
+	skb_push(new_skb, eg->ctrl_info.DH_length);     /* add MAC header */
+	memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length);
+	new_skb->protocol = eth_type_trans(new_skb, dev);
+	new_skb->nh.raw = new_skb->data;
 
 	eg->latest_ip_addr = new_skb->nh.iph->saddr;
-        eg->packets_rcvd++;
-                
-        netif_rx(new_skb);
+	eg->packets_rcvd++;
+	mpc->eg_ops->put(eg);
 
-        return;
+	netif_rx(new_skb);
+
+	return;
 }
 
 static struct atmdev_ops mpc_ops = { /* only send is required */
-        close:	mpoad_close,
-        send:	msg_from_mpoad
+	close:	mpoad_close,
+	send:	msg_from_mpoad
 };
 
 static struct atm_dev mpc_dev = {
-        &mpc_ops,       /* device operations    */
-        NULL,           /* PHY operations       */
-        "mpc",          /* device type name     */
-        42,             /* device index (dummy) */
-        NULL,           /* VCC table            */
-        NULL,           /* last VCC             */
-        NULL,           /* per-device data      */
-        NULL,           /* private PHY data     */
-        { 0 },          /* device flags         */
-        NULL,           /* local ATM address    */
-        { 0 }           /* no ESI               */
-        /* rest of the members will be 0 */
+	&mpc_ops,       /* device operations    */
+	NULL,           /* PHY operations       */
+	"mpc",          /* device type name     */
+	42,             /* device index (dummy) */
+	NULL,           /* VCC table            */
+	NULL,           /* last VCC             */
+	NULL,           /* per-device data      */
+	NULL,           /* private PHY data     */
+	{ 0 },          /* device flags         */
+	NULL,           /* local ATM address    */
+	{ 0 }           /* no ESI               */
+	/* rest of the members will be 0 */
 };
 
 int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
 {
-        struct mpoa_client *mpc;
-        struct lec_priv *priv;
-        
-        if (mpcs == NULL) {
-                init_timer(&mpc_timer);
-                mpc_timer_refresh();
-
-                /* This lets us now how our LECs are doing */
-                register_netdevice_notifier(&mpoa_notifier);
-        }
-        
-        mpc = find_mpc_by_itfnum(arg);
-        if (mpc == NULL) {
-                dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg);
-                mpc = alloc_mpc();
-                mpc->dev_num = arg;
-                mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */
-        }
-        if (mpc->mpoad_vcc) {
-                printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg);
-                return -EADDRINUSE;
-        }
-
-        if (mpc->dev) { /* check if the lec is LANE2 capable */
-                priv = (struct lec_priv *)mpc->dev->priv;
-                if (priv->lane_version < 2)
-                        mpc->dev = NULL;
+	struct mpoa_client *mpc;
+	struct lec_priv *priv;
+	
+	if (mpcs == NULL) {
+		init_timer(&mpc_timer);
+		mpc_timer_refresh();
+
+		/* This lets us now how our LECs are doing */
+		register_netdevice_notifier(&mpoa_notifier);
+	}
+	
+	mpc = find_mpc_by_itfnum(arg);
+	if (mpc == NULL) {
+		dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg);
+		mpc = alloc_mpc();
+		mpc->dev_num = arg;
+		mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */
+	}
+	if (mpc->mpoad_vcc) {
+		printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg);
+		return -EADDRINUSE;
+	}
+
+	if (mpc->dev) { /* check if the lec is LANE2 capable */
+		priv = (struct lec_priv *)mpc->dev->priv;
+		if (priv->lane_version < 2)
+			mpc->dev = NULL;
 		else
-                        priv->lane2_ops->associate_indicator = lane2_assoc_ind;  
-        }
+			priv->lane2_ops->associate_indicator = lane2_assoc_ind;  
+	}
 
-        mpc->mpoad_vcc = vcc;
-        bind_vcc(vcc, &mpc_dev);
+	mpc->mpoad_vcc = vcc;
+	bind_vcc(vcc, &mpc_dev);
 	set_bit(ATM_VF_META,&vcc->flags);
 	set_bit(ATM_VF_READY,&vcc->flags);
 
-        if (mpc->dev) {
-                char empty[ATM_ESA_LEN];
-                memset(empty, 0, ATM_ESA_LEN);
-                
-                start_mpc(mpc, mpc->dev);
-                /* set address if mpcd e.g. gets killed and restarted.
-                 * If we do not do it now we have to wait for the next LE_ARP
-                 */
-                if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 )
-                        send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
-        }
+	if (mpc->dev) {
+		char empty[ATM_ESA_LEN];
+		memset(empty, 0, ATM_ESA_LEN);
+		
+		start_mpc(mpc, mpc->dev);
+		/* set address if mpcd e.g. gets killed and restarted.
+		 * If we do not do it now we have to wait for the next LE_ARP
+		 */
+		if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 )
+			send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
+	}
 
-        MOD_INC_USE_COUNT;
-        return arg;
+	MOD_INC_USE_COUNT;
+	return arg;
 }
 
 static void send_set_mps_ctrl_addr(char *addr, struct mpoa_client *mpc)
 {
-        struct k_message mesg;
+	struct k_message mesg;
 
-        memcpy (mpc->mps_ctrl_addr, addr, ATM_ESA_LEN);
-        
-        mesg.type = SET_MPS_CTRL_ADDR;
-        memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN);
-        msg_to_mpoad(&mesg, mpc);
+	memcpy (mpc->mps_ctrl_addr, addr, ATM_ESA_LEN);
+	
+	mesg.type = SET_MPS_CTRL_ADDR;
+	memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN);
+	msg_to_mpoad(&mesg, mpc);
 
-        return;
+	return;
 }
 
 static void mpoad_close(struct atm_vcc *vcc)
 {
-        unsigned long flags;
-        struct mpoa_client *mpc;
-        struct sk_buff *skb;
-
-        mpc = find_mpc_by_vcc(vcc);
-        if (mpc == NULL) {
-                printk("mpoa: mpoad_close: did not find MPC\n");
-                return;
-        }
-        if (!mpc->mpoad_vcc) {
-                printk("mpoa: mpoad_close: close for non-present mpoad\n");
-                return;
-        }
-        
-        mpc->mpoad_vcc = NULL;
-        if (mpc->dev) {
-                struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv;
-                priv->lane2_ops->associate_indicator = NULL;
-                stop_mpc(mpc);
-        }
-
-        /* clear the caches */
-        write_lock_irqsave(&mpc->ingress_lock, flags);
-        while(mpc->in_ops->cache_remove(mpc->in_cache, mpc));
-        write_unlock_irqrestore(&mpc->ingress_lock, flags);
-
-        write_lock_irqsave(&mpc->egress_lock, flags);
-        while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc));
-        write_unlock_irqrestore(&mpc->egress_lock, flags);
+	struct mpoa_client *mpc;
+	struct sk_buff *skb;
+
+	mpc = find_mpc_by_vcc(vcc);
+	if (mpc == NULL) {
+		printk("mpoa: mpoad_close: did not find MPC\n");
+		return;
+	}
+	if (!mpc->mpoad_vcc) {
+		printk("mpoa: mpoad_close: close for non-present mpoad\n");
+		return;
+	}
+	
+	mpc->mpoad_vcc = NULL;
+	if (mpc->dev) {
+		struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv;
+		priv->lane2_ops->associate_indicator = NULL;
+		stop_mpc(mpc);
+	}
+
+	mpc->in_ops->destroy_cache(mpc);
+	mpc->eg_ops->destroy_cache(mpc);
 
 	while ( (skb = skb_dequeue(&vcc->recvq)) ){
-                atm_return(vcc, skb->truesize);
-                kfree_skb(skb);
-        }
-        
-        printk("mpoa: (%s) going down\n",
-                (mpc->dev) ? mpc->dev->name : "<unknown>");
-        MOD_DEC_USE_COUNT;
+		atm_return(vcc, skb->truesize);
+		kfree_skb(skb);
+	}
+	
+	printk("mpoa: (%s) going down\n",
+		(mpc->dev) ? mpc->dev->name : "<unknown>");
+	MOD_DEC_USE_COUNT;
 
-        return;
+	return;
 }
 
 /*
@@ -862,163 +864,163 @@
  */
 static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb)
 {
-        
-        struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
-        struct k_message *mesg = (struct k_message*)skb->data;
-        atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse);
-        
-        if (mpc == NULL) {
-                printk("mpoa: msg_from_mpoad: no mpc found\n");
-                return 0;
-        }
-        dprintk("mpoa: (%s) msg_from_mpoad:", (mpc->dev) ? mpc->dev->name : "<unknown>");
-        switch(mesg->type) {
-        case MPOA_RES_REPLY_RCVD:
-	        dprintk(" mpoa_res_reply_rcvd\n");
-                MPOA_res_reply_rcvd(mesg, mpc);
-                break;
-        case MPOA_TRIGGER_RCVD:
-	        dprintk(" mpoa_trigger_rcvd\n");
-                MPOA_trigger_rcvd(mesg, mpc);
-                break;
-        case INGRESS_PURGE_RCVD:
-                dprintk(" nhrp_purge_rcvd\n");
-                ingress_purge_rcvd(mesg, mpc);
-                break;
-        case EGRESS_PURGE_RCVD:
-	        dprintk(" egress_purge_reply_rcvd\n");
-                egress_purge_rcvd(mesg, mpc);
-                break;
-        case MPS_DEATH:
-	        dprintk(" mps_death\n");
-                mps_death(mesg, mpc);
-                break;
-        case CACHE_IMPOS_RCVD:
-	        dprintk(" cache_impos_rcvd\n");
-                MPOA_cache_impos_rcvd(mesg, mpc);
-                break;
-        case SET_MPC_CTRL_ADDR:
-                dprintk(" set_mpc_ctrl_addr\n");
-                set_mpc_ctrl_addr_rcvd(mesg, mpc);
-                break;
+	
+	struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
+	struct k_message *mesg = (struct k_message*)skb->data;
+	atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse);
+	
+	if (mpc == NULL) {
+		printk("mpoa: msg_from_mpoad: no mpc found\n");
+		return 0;
+	}
+	dprintk("mpoa: (%s) msg_from_mpoad:", (mpc->dev) ? mpc->dev->name : "<unknown>");
+	switch(mesg->type) {
+	case MPOA_RES_REPLY_RCVD:
+		dprintk(" mpoa_res_reply_rcvd\n");
+		MPOA_res_reply_rcvd(mesg, mpc);
+		break;
+	case MPOA_TRIGGER_RCVD:
+		dprintk(" mpoa_trigger_rcvd\n");
+		MPOA_trigger_rcvd(mesg, mpc);
+		break;
+	case INGRESS_PURGE_RCVD:
+		dprintk(" nhrp_purge_rcvd\n");
+		ingress_purge_rcvd(mesg, mpc);
+		break;
+	case EGRESS_PURGE_RCVD:
+		dprintk(" egress_purge_reply_rcvd\n");
+		egress_purge_rcvd(mesg, mpc);
+		break;
+	case MPS_DEATH:
+		dprintk(" mps_death\n");
+		mps_death(mesg, mpc);
+		break;
+	case CACHE_IMPOS_RCVD:
+		dprintk(" cache_impos_rcvd\n");
+		MPOA_cache_impos_rcvd(mesg, mpc);
+		break;
+	case SET_MPC_CTRL_ADDR:
+		dprintk(" set_mpc_ctrl_addr\n");
+		set_mpc_ctrl_addr_rcvd(mesg, mpc);
+		break;
 	case SET_MPS_MAC_ADDR:
-	        dprintk(" set_mps_mac_addr\n");
+		dprintk(" set_mps_mac_addr\n");
 		set_mps_mac_addr_rcvd(mesg, mpc);
 		break;
 	case CLEAN_UP_AND_EXIT:
-                dprintk(" clean_up_and_exit\n");
-                clean_up(mesg, mpc, DIE);
-                break;
-        case RELOAD:
-                dprintk(" reload\n");
-                clean_up(mesg, mpc, RELOAD);
-                break;
-        case SET_MPC_PARAMS:
-                dprintk(" set_mpc_params\n");
-                mpc->parameters = mesg->content.params;
-                break;
-        default:
-                dprintk(" unknown message %d\n", mesg->type);
-                break;
-        }
-        kfree_skb(skb);
+		dprintk(" clean_up_and_exit\n");
+		clean_up(mesg, mpc, DIE);
+		break;
+	case RELOAD:
+		dprintk(" reload\n");
+		clean_up(mesg, mpc, RELOAD);
+		break;
+	case SET_MPC_PARAMS:
+		dprintk(" set_mpc_params\n");
+		mpc->parameters = mesg->content.params;
+		break;
+	default:
+		dprintk(" unknown message %d\n", mesg->type);
+		break;
+	}
+	kfree_skb(skb);
 
-        return 0;
+	return 0;
 }
 
+/* Remember that this function may not do things that sleep */
 int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc)
 {
-        struct sk_buff *skb;
+	struct sk_buff *skb;
+
+	if (mpc == NULL || !mpc->mpoad_vcc) {
+		printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type);
+		return -ENXIO;
+	}
 
-        if (mpc == NULL || !mpc->mpoad_vcc) {
-                printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type);
-                return -ENXIO;
-        }
-
-        skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
-        if (skb == NULL)
-                return -ENOMEM;
-        skb_put(skb, sizeof(struct k_message));
-        memcpy(skb->data, mesg, sizeof(struct k_message));
-        atm_force_charge(mpc->mpoad_vcc, skb->truesize);
-        skb_queue_tail(&mpc->mpoad_vcc->recvq, skb);
-        wake_up(&mpc->mpoad_vcc->sleep);
+	skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+	skb_put(skb, sizeof(struct k_message));
+	memcpy(skb->data, mesg, sizeof(struct k_message));
+	atm_force_charge(mpc->mpoad_vcc, skb->truesize);
+	skb_queue_tail(&mpc->mpoad_vcc->recvq, skb);
+	wake_up(&mpc->mpoad_vcc->sleep);
 
-        return 0;
+	return 0;
 }
 
 static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev_ptr)
 {
-        struct net_device *dev;
-        struct mpoa_client *mpc;
-        struct lec_priv *priv;
-
-        dev = (struct net_device *)dev_ptr;
-        if (dev->name == NULL || strncmp(dev->name, "lec", 3))
-                return NOTIFY_DONE; /* we are only interested in lec:s */
-        
-        switch (event) {
-        case NETDEV_REGISTER:       /* a new lec device was allocated */
-                priv = (struct lec_priv *)dev->priv;
-                if (priv->lane_version < 2)
-                        break;
-                priv->lane2_ops->associate_indicator = lane2_assoc_ind;
-                mpc = find_mpc_by_itfnum(priv->itfnum);
-                if (mpc == NULL) {
-                        dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n",
-                               dev->name);
-                        mpc = alloc_mpc();
-                        if (mpc == NULL) {
-                                printk("mpoa: mpoa_event_listener: no new mpc");
-                                break;
-                        }
-                }
-                mpc->dev_num = priv->itfnum;
-                mpc->dev = dev;
-                dprintk("mpoa: (%s) was initialized\n", dev->name);
-                break;
-        case NETDEV_UNREGISTER:
-                /* the lec device was deallocated */
-                mpc = find_mpc_by_lec(dev);
-                if (mpc == NULL)
-                        break;
-                dprintk("mpoa: device (%s) was deallocated\n", dev->name);
-                stop_mpc(mpc);
-                mpc->dev = NULL;
-                break;
-        case NETDEV_UP:
-                /* the dev was ifconfig'ed up */
-                mpc = find_mpc_by_lec(dev);
-                if (mpc == NULL)
-                        break;
-                if (mpc->mpoad_vcc != NULL) {
-                        start_mpc(mpc, dev);
-                }
-                break;
-        case NETDEV_DOWN:
-                /* the dev was ifconfig'ed down */
-                /* this means dev->start == 0 and
-                 * the flow of packets from the
-                 * upper layer stops
-                 */
-                mpc = find_mpc_by_lec(dev);
-                if (mpc == NULL)
-                        break;
-                if (mpc->mpoad_vcc != NULL) {
-                        stop_mpc(mpc);
-                }
-                break;
-        case NETDEV_REBOOT:
-        case NETDEV_CHANGE:
-        case NETDEV_CHANGEMTU:
-        case NETDEV_CHANGEADDR:
-        case NETDEV_GOING_DOWN:
-                break;
-        default:
-                break;
-        }
+	struct net_device *dev;
+	struct mpoa_client *mpc;
+	struct lec_priv *priv;
+
+	dev = (struct net_device *)dev_ptr;
+	if (dev->name == NULL || strncmp(dev->name, "lec", 3))
+		return NOTIFY_DONE; /* we are only interested in lec:s */
+	
+	switch (event) {
+	case NETDEV_REGISTER:       /* a new lec device was allocated */
+		priv = (struct lec_priv *)dev->priv;
+		if (priv->lane_version < 2)
+			break;
+		priv->lane2_ops->associate_indicator = lane2_assoc_ind;
+		mpc = find_mpc_by_itfnum(priv->itfnum);
+		if (mpc == NULL) {
+			dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n",
+			       dev->name);
+			mpc = alloc_mpc();
+			if (mpc == NULL) {
+				printk("mpoa: mpoa_event_listener: no new mpc");
+				break;
+			}
+		}
+		mpc->dev_num = priv->itfnum;
+		mpc->dev = dev;
+		dprintk("mpoa: (%s) was initialized\n", dev->name);
+		break;
+	case NETDEV_UNREGISTER:
+		/* the lec device was deallocated */
+		mpc = find_mpc_by_lec(dev);
+		if (mpc == NULL)
+			break;
+		dprintk("mpoa: device (%s) was deallocated\n", dev->name);
+		stop_mpc(mpc);
+		mpc->dev = NULL;
+		break;
+	case NETDEV_UP:
+		/* the dev was ifconfig'ed up */
+		mpc = find_mpc_by_lec(dev);
+		if (mpc == NULL)
+			break;
+		if (mpc->mpoad_vcc != NULL) {
+			start_mpc(mpc, dev);
+		}
+		break;
+	case NETDEV_DOWN:
+		/* the dev was ifconfig'ed down */
+		/* this means that the flow of packets from the
+		 * upper layer stops
+		 */
+		mpc = find_mpc_by_lec(dev);
+		if (mpc == NULL)
+			break;
+		if (mpc->mpoad_vcc != NULL) {
+			stop_mpc(mpc);
+		}
+		break;
+	case NETDEV_REBOOT:
+	case NETDEV_CHANGE:
+	case NETDEV_CHANGEMTU:
+	case NETDEV_CHANGEADDR:
+	case NETDEV_GOING_DOWN:
+		break;
+	default:
+		break;
+	}
 
-        return NOTIFY_DONE;
+	return NOTIFY_DONE;
 }
 
 /*
@@ -1027,33 +1029,36 @@
  */
 
 
-static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *client)
+static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc)
 {
-        uint32_t dst_ip = msg->content.in_info.in_dst_ip;
-        in_cache_entry *entry;
+	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
+	in_cache_entry *entry;
 
-	entry = client->in_ops->search(dst_ip, client);
-        if( entry == NULL ){
-                entry = client->in_ops->new_entry(dst_ip, client);
-                entry->entry_state = INGRESS_RESOLVING;
+	entry = mpc->in_ops->get(dst_ip, mpc);
+	if(entry == NULL){
+		entry = mpc->in_ops->add_entry(dst_ip, mpc);
+		entry->entry_state = INGRESS_RESOLVING;
 		msg->type = SND_MPOA_RES_RQST;
-                msg->content.in_info = entry->ctrl_info;
-		msg_to_mpoad(msg,client);
+		msg->content.in_info = entry->ctrl_info;
+		msg_to_mpoad(msg, mpc);
 		do_gettimeofday(&(entry->reply_wait));
+		mpc->in_ops->put(entry);
 		return;
-        }
-        
-        if( entry->entry_state == INGRESS_INVALID ){
-                entry->entry_state = INGRESS_RESOLVING;
+	}
+	
+	if(entry->entry_state == INGRESS_INVALID){
+		entry->entry_state = INGRESS_RESOLVING;
 		msg->type = SND_MPOA_RES_RQST;
-                msg->content.in_info = entry->ctrl_info;
-		msg_to_mpoad(msg,client);
+		msg->content.in_info = entry->ctrl_info;
+		msg_to_mpoad(msg, mpc);
 		do_gettimeofday(&(entry->reply_wait));
-                return;
-        }
-        
-        printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n",
-                (client->dev) ? client->dev->name : "<unknown>");
+		mpc->in_ops->put(entry);
+		return;
+	}
+	
+	printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n",
+		(mpc->dev) ? mpc->dev->name : "<unknown>");
+	mpc->in_ops->put(entry);
 	return;
 }
 
@@ -1061,30 +1066,36 @@
  * Things get complicated because we have to check if there's an egress
  * shortcut with suitable traffic parameters we could use. 
  */
-static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry){
-        uint32_t dst_ip = msg->content.in_info.in_dst_ip;
-        unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
+static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry)
+{
+	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
+	unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
 	struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip);
-	eg_cache_entry *eg_entry = client->eg_ops->search_by_src_ip(dst_ip, client);
+	eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client);
+
 	if(eg_entry && eg_entry->shortcut){
-	        if(eg_entry->shortcut->qos.txtp.traffic_class &
+		if(eg_entry->shortcut->qos.txtp.traffic_class &
 		   msg->qos.txtp.traffic_class &
 		   (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)){
-		            if(eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR)
-			            entry->shortcut = eg_entry->shortcut;
+			    if(eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR)
+				    entry->shortcut = eg_entry->shortcut;
 			    else if(eg_entry->shortcut->qos.txtp.max_pcr > 0)
-			            entry->shortcut = eg_entry->shortcut;
+				    entry->shortcut = eg_entry->shortcut;
 		}
 	 	if(entry->shortcut){
-		        dprintk("mpoa: (%s) using egress SVC to reach %d.%d.%d.%d\n",client->dev->name, ip[0], ip[1], ip[2], ip[3]);
+			dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(ip));
+			client->eg_ops->put(eg_entry);
 			return;
 		}
 	}
+	if (eg_entry != NULL)
+		client->eg_ops->put(eg_entry);
+
 	/* No luck in the egress cache we must open an ingress SVC */
 	msg->type = OPEN_INGRESS_SVC;
 	if (qos && (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class))
 	{
-	        msg->qos = qos->qos;
+		msg->qos = qos->qos;
 		printk("mpoa: (%s) trying to get a CBR shortcut\n",client->dev->name);
     	}
 	else memset(&msg->qos,0,sizeof(struct atm_qos));
@@ -1092,45 +1103,49 @@
 	return;
 }
 
-static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *client)
+static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
 {
 	unsigned char *ip;
 
-        uint32_t dst_ip = msg->content.in_info.in_dst_ip;
-        in_cache_entry *entry = client->in_ops->search(dst_ip, client);
+	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
+	in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc);
 	ip = (unsigned char *)&dst_ip;
-        dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %d.%d.%d.%d\n", client->dev->name, ip[0], ip[1], ip[2], ip[3]);
-        ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", client->dev->name, entry);
-        if(entry == NULL){
-                printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", client->dev->name);
-                return;
-        }
-        ddprintk(" entry_state = %d ", entry->entry_state);	
-
-        if (entry->entry_state == INGRESS_RESOLVED) {
-                printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", client->dev->name);
-                return;
-        }
-
-        entry->ctrl_info = msg->content.in_info;
-        do_gettimeofday(&(entry->tv));
-        do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */
-        entry->refresh_time = 0;
-        ddprintk("entry->shortcut = %p\n", entry->shortcut);
+	dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(ip));
+	ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry);
+	if(entry == NULL){
+		printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name);
+		return;
+	}
+	ddprintk(" entry_state = %d ", entry->entry_state);	
+
+	if (entry->entry_state == INGRESS_RESOLVED) {
+		printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", mpc->dev->name);
+		mpc->in_ops->put(entry);
+		return;
+	}
+
+	entry->ctrl_info = msg->content.in_info;
+	do_gettimeofday(&(entry->tv));
+	do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */
+	entry->refresh_time = 0;
+	ddprintk("entry->shortcut = %p\n", entry->shortcut);
 
 	if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL){
-	        entry->entry_state = INGRESS_RESOLVED; 
+		entry->entry_state = INGRESS_RESOLVED; 
+		mpc->in_ops->put(entry);
 		return; /* Shortcut already open... */
 	}
 
 	if (entry->shortcut != NULL) {
 		printk("mpoa: (%s) MPOA_res_reply_rcvd: entry->shortcut != NULL, impossible!\n",
-		       client->dev->name);
+		       mpc->dev->name);
+		mpc->in_ops->put(entry);
 		return;
 	}
 	
-	check_qos_and_open_shortcut(msg, client, entry);
+	check_qos_and_open_shortcut(msg, mpc, entry);
 	entry->entry_state = INGRESS_RESOLVED;
+	mpc->in_ops->put(entry);
 
 	return;
 
@@ -1138,73 +1153,79 @@
 
 static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
 {
-        uint32_t dst_ip = msg->content.in_info.in_dst_ip;
-        uint32_t mask = msg->ip_mask;
+	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
+	uint32_t mask = msg->ip_mask;
 	unsigned char *ip = (unsigned char *)&dst_ip;
+	in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
 
-        in_cache_entry *entry = mpc->in_ops->search_with_mask(dst_ip, mpc, mask);
-        if( entry == NULL ){
-                printk("mpoa: (%s) ingress_purge_rcvd: recieved a purge for an entry that doesn't exist, ", mpc->dev->name);
-                printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
-                return;
-        }
-	while(entry != NULL){
-	        dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" ,
-		       mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
-		mpc->in_ops->cache_remove(entry, mpc);
-		entry = mpc->in_ops->search_with_mask(dst_ip, mpc, mask);
+	if(entry == NULL){
+		printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ", mpc->dev->name);
+		printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
+		return;
 	}
-        return;
+
+	do {
+		dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" ,
+			mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+		write_lock_bh(&mpc->ingress_lock);
+		mpc->in_ops->remove_entry(entry, mpc);
+		write_unlock_bh(&mpc->ingress_lock);
+		mpc->in_ops->put(entry);
+		entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
+	} while (entry != NULL);
+
+	return;
 } 
 
 static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
 {
-        unsigned long flags;
-        uint32_t cache_id = msg->content.eg_info.cache_id;
-        eg_cache_entry *entry = mpc->eg_ops->search_by_cache_id(cache_id, mpc);
-        
-        if( entry == NULL ){
-                printk("mpoa: (%s) egress_purge_rcvd: received a purge reply for an entry that doesn't exist\n", mpc->dev->name);
-                return;
-        }
-
-        write_lock_irqsave(&mpc->egress_lock, flags);
-        mpc->eg_ops->cache_remove(entry, mpc);
-        write_unlock_irqrestore(&mpc->egress_lock, flags);
+	uint32_t cache_id = msg->content.eg_info.cache_id;
+	eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc);
+	
+	if (entry == NULL) {
+		dprintk("mpoa: (%s) egress_purge_rcvd: purge for a non-existing entry\n", mpc->dev->name);
+		return;
+	}
+
+	write_lock_irq(&mpc->egress_lock);
+	mpc->eg_ops->remove_entry(entry, mpc);
+	write_unlock_irq(&mpc->egress_lock);
 
-        return;
+	mpc->eg_ops->put(entry);
+
+	return;
 } 
 
 static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
 {
-        struct k_message *purge_msg;
-        struct sk_buff *skb;
+	struct k_message *purge_msg;
+	struct sk_buff *skb;
 
-        dprintk("mpoa: purge_egress_shortcut: entering\n");
-        if (vcc == NULL) {
-                printk("mpoa: purge_egress_shortcut: vcc == NULL\n");
-                return;
-        }
-
-        skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
-        if (skb == NULL) {
-                 printk("mpoa: purge_egress_shortcut: out of memory\n");
-                return;
-        }
-
-        skb_put(skb, sizeof(struct k_message));
-        memset(skb->data, 0, sizeof(struct k_message));
-        purge_msg = (struct k_message *)skb->data;
-        purge_msg->type = DATA_PLANE_PURGE;
-        if (entry != NULL)
-                purge_msg->content.eg_info = entry->ctrl_info;
-
-        atm_force_charge(vcc, skb->truesize);
-        skb_queue_tail(&vcc->recvq, skb);
-        wake_up(&vcc->sleep);
-        dprintk("mpoa: purge_egress_shortcut: exiting:\n");
+	dprintk("mpoa: purge_egress_shortcut: entering\n");
+	if (vcc == NULL) {
+		printk("mpoa: purge_egress_shortcut: vcc == NULL\n");
+		return;
+	}
 
-        return;
+	skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
+	if (skb == NULL) {
+		 printk("mpoa: purge_egress_shortcut: out of memory\n");
+		return;
+	}
+
+	skb_put(skb, sizeof(struct k_message));
+	memset(skb->data, 0, sizeof(struct k_message));
+	purge_msg = (struct k_message *)skb->data;
+	purge_msg->type = DATA_PLANE_PURGE;
+	if (entry != NULL)
+		purge_msg->content.eg_info = entry->ctrl_info;
+
+	atm_force_charge(vcc, skb->truesize);
+	skb_queue_tail(&vcc->recvq, skb);
+	wake_up(&vcc->sleep);
+	dprintk("mpoa: purge_egress_shortcut: exiting:\n");
+
+	return;
 }
 
 /*
@@ -1213,104 +1234,102 @@
  */
 static void mps_death( struct k_message * msg, struct mpoa_client * mpc )
 {
+	eg_cache_entry *entry;
 
-        unsigned long flags;
-        eg_cache_entry *entry;
+	dprintk("mpoa: (%s) mps_death:\n", mpc->dev->name);
 
-        dprintk("mpoa: (%s) mps_death:\n", mpc->dev->name);
+	if(memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)){
+		printk("mpoa: (%s) mps_death: wrong MPS\n", mpc->dev->name);
+		return;
+	}
+
+	/* FIXME: This knows too much of the cache structure */
+	read_lock_irq(&mpc->egress_lock);
+	entry = mpc->eg_cache;
+	while (entry != NULL) {
+		purge_egress_shortcut(entry->shortcut, entry);
+		entry = entry->next;
+	}
+	read_unlock_irq(&mpc->egress_lock);
 
-        if(memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)){
-                printk("mpoa: (%s) mps_death: wrong MPS\n", mpc->dev->name);
-                return;
-        }
-
-        entry = mpc->eg_cache;
-        while (entry != NULL) {
-                purge_egress_shortcut(entry->shortcut, entry);
-                entry = entry->next;
-        }
-
-        write_lock_irqsave(&mpc->ingress_lock, flags);
-        while(mpc->in_ops->cache_remove(mpc->in_cache, mpc));
-        write_unlock_irqrestore(&mpc->ingress_lock, flags);
-
-        write_lock_irqsave(&mpc->egress_lock, flags);
-        while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc));
-        write_unlock_irqrestore(&mpc->egress_lock, flags);
-
-        return;
-}
-
-static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * mpc){
-
-        uint16_t holding_time;
-        unsigned long flags;
-        eg_cache_entry *entry = mpc->eg_ops->search_by_cache_id(msg->content.eg_info.cache_id, mpc);
-        
-        holding_time = msg->content.eg_info.holding_time;
-        dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n",
-               mpc->dev->name, entry, holding_time);
-        if(entry == NULL && holding_time) {
-                mpc->eg_ops->new_entry(msg, mpc);
-                return;
-        }
-        if(holding_time){
-                mpc->eg_ops->update(entry, holding_time);
-                return;
-        }
-        
-        write_lock_irqsave(&mpc->egress_lock, flags);
-        mpc->eg_ops->cache_remove(entry, mpc);
-        write_unlock_irqrestore(&mpc->egress_lock, flags);
+	mpc->in_ops->destroy_cache(mpc);
+	mpc->eg_ops->destroy_cache(mpc);
 
-        
-        return;
+	return;
+}
+
+static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * mpc)
+{
+	uint16_t holding_time;
+	eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(msg->content.eg_info.cache_id, mpc);
+	
+	holding_time = msg->content.eg_info.holding_time;
+	dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n",
+	       mpc->dev->name, entry, holding_time);
+	if(entry == NULL && holding_time) {
+		entry = mpc->eg_ops->add_entry(msg, mpc);
+		mpc->eg_ops->put(entry);
+		return;
+	}
+	if(holding_time){
+		mpc->eg_ops->update(entry, holding_time);
+		return;
+	}
+	
+	write_lock_irq(&mpc->egress_lock);
+	mpc->eg_ops->remove_entry(entry, mpc);
+	write_unlock_irq(&mpc->egress_lock);
+
+	mpc->eg_ops->put(entry);
+	
+	return;
 }
 
 static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc)
 {
-        struct lec_priv *priv;
-        int i, retval ;
+	struct lec_priv *priv;
+	int i, retval ;
 
-        uint8_t tlv[4 + 1 + 1 + 1 + ATM_ESA_LEN];
+	uint8_t tlv[4 + 1 + 1 + 1 + ATM_ESA_LEN];
 
-        tlv[0] = 00; tlv[1] = 0xa0; tlv[2] = 0x3e; tlv[3] = 0x2a; /* type  */
-        tlv[4] = 1 + 1 + ATM_ESA_LEN;  /* length                           */
-        tlv[5] = 0x02;                 /* MPOA client                      */
-        tlv[6] = 0x00;                 /* number of MPS MAC addresses      */
-
-        memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */
-        memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN);
-
-        dprintk("mpoa: (%s) setting MPC ctrl ATM address to ",
-               (mpc->dev) ? mpc->dev->name : "<unknown>");
-        for (i = 7; i < sizeof(tlv); i++)
-                dprintk("%02x ", tlv[i]);
-        dprintk("\n");
-
-        if (mpc->dev) {
-                priv = (struct lec_priv *)mpc->dev->priv;
-                retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv));
-                if (retval == 0)
-                        printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name);
-                retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL);
-                if (retval < 0)
-                        printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc->dev->name);
-        }
-
-        return;
-}
-
-static void set_mps_mac_addr_rcvd(struct k_message *msg, struct mpoa_client *client){
-
-        if(client->number_of_mps_macs)
-                kfree(client->mps_macs);
-        client->number_of_mps_macs = 0;
+	tlv[0] = 00; tlv[1] = 0xa0; tlv[2] = 0x3e; tlv[3] = 0x2a; /* type  */
+	tlv[4] = 1 + 1 + ATM_ESA_LEN;  /* length                           */
+	tlv[5] = 0x02;                 /* MPOA client                      */
+	tlv[6] = 0x00;                 /* number of MPS MAC addresses      */
+
+	memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */
+	memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN);
+
+	dprintk("mpoa: (%s) setting MPC ctrl ATM address to ",
+	       (mpc->dev) ? mpc->dev->name : "<unknown>");
+	for (i = 7; i < sizeof(tlv); i++)
+		dprintk("%02x ", tlv[i]);
+	dprintk("\n");
+
+	if (mpc->dev) {
+		priv = (struct lec_priv *)mpc->dev->priv;
+		retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv));
+		if (retval == 0)
+			printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name);
+		retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL);
+		if (retval < 0)
+			printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc->dev->name);
+	}
+
+	return;
+}
+
+static void set_mps_mac_addr_rcvd(struct k_message *msg, struct mpoa_client *client)
+{
+
+	if(client->number_of_mps_macs)
+		kfree(client->mps_macs);
+	client->number_of_mps_macs = 0;
 	client->mps_macs = kmalloc(ETH_ALEN,GFP_KERNEL);
-        if (client->mps_macs == NULL) {
-	        printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n");
-                return;
-        }
+	if (client->mps_macs == NULL) {
+		printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n");
+		return;
+	}
 	client->number_of_mps_macs = 1;
 	memcpy(client->mps_macs, msg->MPS_ctrl, ETH_ALEN);
 	
@@ -1320,22 +1339,23 @@
 /*
  * purge egress cache and tell daemon to 'action' (DIE, RELOAD)
  */
-static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action){
+static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action)
+{
 
-        unsigned long flags;
-        eg_cache_entry *entry;
+	eg_cache_entry *entry;
 	msg->type = SND_EGRESS_PURGE;
 
 
-        read_lock_irqsave(&mpc->egress_lock, flags);
-        entry = mpc->eg_cache;
-	while(entry != NULL){
-	            msg->content.eg_info = entry->ctrl_info;
-                    dprintk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id);
+	/* FIXME: This knows too much of the cache structure */
+	read_lock_irq(&mpc->egress_lock);
+	entry = mpc->eg_cache;
+	while (entry != NULL){
+		    msg->content.eg_info = entry->ctrl_info;
+		    dprintk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id);
 		    msg_to_mpoad(msg, mpc);
 		    entry = entry->next;
 	}
-        read_unlock_irqrestore(&mpc->egress_lock, flags);
+	read_unlock_irq(&mpc->egress_lock);
 
 	msg->type = action;
 	msg_to_mpoad(msg, mpc);
@@ -1344,116 +1364,116 @@
 
 static void mpc_timer_refresh()
 {
-        mpc_timer.expires = jiffies + (MPC_P2 * HZ);
-        mpc_timer.data = mpc_timer.expires;
-        mpc_timer.function = mpc_cache_check;
-        add_timer(&mpc_timer);
-        
-        return;
+	mpc_timer.expires = jiffies + (MPC_P2 * HZ);
+	mpc_timer.data = mpc_timer.expires;
+	mpc_timer.function = mpc_cache_check;
+	add_timer(&mpc_timer);
+	
+	return;
 }
 
 static void mpc_cache_check( unsigned long checking_time  )
 {
-        struct mpoa_client *mpc = mpcs;
-        static unsigned long previous_resolving_check_time = 0;
-        static unsigned long previous_refresh_time = 0;
-        
-        while( mpc != NULL ){
-                mpc->in_ops->clear_count(mpc);
+	struct mpoa_client *mpc = mpcs;
+	static unsigned long previous_resolving_check_time = 0;
+	static unsigned long previous_refresh_time = 0;
+	
+	while( mpc != NULL ){
+		mpc->in_ops->clear_count(mpc);
 		mpc->eg_ops->clear_expired(mpc);
-                if(checking_time - previous_resolving_check_time > mpc->parameters.mpc_p4 * HZ ){
-                        mpc->in_ops->check_resolving(mpc);
-                        previous_resolving_check_time = checking_time;
-                }
-                if(checking_time - previous_refresh_time > mpc->parameters.mpc_p5 * HZ ){
-                        mpc->in_ops->refresh(mpc);
-                        previous_refresh_time = checking_time;
-                }
-                mpc = mpc->next;
-        }
-        mpc_timer_refresh();
-        
-        return;
+		if(checking_time - previous_resolving_check_time > mpc->parameters.mpc_p4 * HZ ){
+			mpc->in_ops->check_resolving(mpc);
+			previous_resolving_check_time = checking_time;
+		}
+		if(checking_time - previous_refresh_time > mpc->parameters.mpc_p5 * HZ ){
+			mpc->in_ops->refresh(mpc);
+			previous_refresh_time = checking_time;
+		}
+		mpc = mpc->next;
+	}
+	mpc_timer_refresh();
+	
+	return;
 }
 
 void atm_mpoa_init_ops(struct atm_mpoa_ops *ops)
 {
-        ops->mpoad_attach = atm_mpoa_mpoad_attach;
-        ops->vcc_attach = atm_mpoa_vcc_attach;
+	ops->mpoad_attach = atm_mpoa_mpoad_attach;
+	ops->vcc_attach = atm_mpoa_vcc_attach;
 
 #ifdef CONFIG_PROC_FS
 	if(mpc_proc_init() != 0)
-	        printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n");
+		printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n");
 	else
-	        printk(KERN_INFO "mpoa: /proc/mpoa initialized\n");
+		printk(KERN_INFO "mpoa: /proc/mpoa initialized\n");
 #endif
 
-        printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
+	printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
 
-        return;
+	return;
 }
 
 #ifdef MODULE
 int init_module(void)
 {
-        extern struct atm_mpoa_ops atm_mpoa_ops;
+	extern struct atm_mpoa_ops atm_mpoa_ops;
 
 	atm_mpoa_init_ops(&atm_mpoa_ops);
 
-        return 0;
+	return 0;
 }
 
 void cleanup_module(void)
 {
-        extern struct atm_mpoa_ops atm_mpoa_ops;
-        struct mpoa_client *mpc, *tmp;
-        struct atm_mpoa_qos *qos, *nextqos;
-        struct lec_priv *priv;
-
-        if (MOD_IN_USE) {
-                printk("mpc.c: module in use\n");
-                return;
-        }
+	extern struct atm_mpoa_ops atm_mpoa_ops;
+	struct mpoa_client *mpc, *tmp;
+	struct atm_mpoa_qos *qos, *nextqos;
+	struct lec_priv *priv;
+
+	if (MOD_IN_USE) {
+		printk("mpc.c: module in use\n");
+		return;
+	}
 #ifdef CONFIG_PROC_FS
 	mpc_proc_clean();
 #endif
 
-        del_timer(&mpc_timer);
-        unregister_netdevice_notifier(&mpoa_notifier);
-        atm_mpoa_ops.mpoad_attach = NULL;
-        atm_mpoa_ops.vcc_attach = NULL;
-
-        mpc = mpcs;
-        mpcs = NULL;
-        while (mpc != NULL) {
-                tmp = mpc->next;
-                if (mpc->dev != NULL) {
-                        stop_mpc(mpc);
-                        priv = (struct lec_priv *)mpc->dev->priv;
-                        if (priv->lane2_ops != NULL)
-                                priv->lane2_ops->associate_indicator = NULL;
-                }
-                ddprintk("mpoa: cleanup_module: about to clear caches\n");
-                while(mpc->in_ops->cache_remove(mpc->in_cache, mpc));
-                while(mpc->eg_ops->cache_remove(mpc->eg_cache, mpc));        
-                ddprintk("mpoa: cleanup_module: caches cleared\n");
-                kfree(mpc->mps_macs);
-                memset(mpc, 0, sizeof(struct mpoa_client));
-                ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc);
-                kfree(mpc);
-                ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp);
-                mpc = tmp;
-        }
-
-        qos = qos_head;
-        qos_head = NULL;
-        while (qos != NULL) {
-                nextqos = qos->next;
-                dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos);
-                kfree(qos);
-                qos = nextqos;
-        }
+	del_timer(&mpc_timer);
+	unregister_netdevice_notifier(&mpoa_notifier);
+	atm_mpoa_ops.mpoad_attach = NULL;
+	atm_mpoa_ops.vcc_attach = NULL;
+
+	mpc = mpcs;
+	mpcs = NULL;
+	while (mpc != NULL) {
+		tmp = mpc->next;
+		if (mpc->dev != NULL) {
+			stop_mpc(mpc);
+			priv = (struct lec_priv *)mpc->dev->priv;
+			if (priv->lane2_ops != NULL)
+				priv->lane2_ops->associate_indicator = NULL;
+		}
+		ddprintk("mpoa: cleanup_module: about to clear caches\n");
+		mpc->in_ops->destroy_cache(mpc);
+		mpc->eg_ops->destroy_cache(mpc);
+		ddprintk("mpoa: cleanup_module: caches cleared\n");
+		kfree(mpc->mps_macs);
+		memset(mpc, 0, sizeof(struct mpoa_client));
+		ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc);
+		kfree(mpc);
+		ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp);
+		mpc = tmp;
+	}
 
-        return;
+	qos = qos_head;
+	qos_head = NULL;
+	while (qos != NULL) {
+		nextqos = qos->next;
+		dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos);
+		kfree(qos);
+		qos = nextqos;
+	}
+
+	return;
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/mpoa_caches.c linux/net/atm/mpoa_caches.c
--- v2.3.99-pre5/linux/net/atm/mpoa_caches.c	Thu Feb 10 17:11:23 2000
+++ linux/net/atm/mpoa_caches.c	Fri Apr 14 09:48:47 2000
@@ -22,165 +22,159 @@
 #define ddprintk(format,args...)
 #endif
 
-static in_cache_entry *in_cache_search(uint32_t dst_ip, 
-				       struct mpoa_client *client)
+static in_cache_entry *in_cache_get(uint32_t dst_ip,
+				    struct mpoa_client *client)
 {
-        unsigned long flags;
-        in_cache_entry *entry;
+	in_cache_entry *entry;
 
-        read_lock_irqsave(&client->ingress_lock, flags);
-        entry = client->in_cache;
-        while(entry != NULL){
-                if( entry->ctrl_info.in_dst_ip == dst_ip ){
-                        read_unlock_irqrestore(&client->ingress_lock, flags);
-                        return entry;
-                }
-                entry = entry->next;
-        }
-        read_unlock_irqrestore(&client->ingress_lock, flags);
-
-        return NULL;
-}
-
-static in_cache_entry *in_cache_search_with_mask(uint32_t dst_ip,
-						 struct mpoa_client *client,
-						 uint32_t mask){
-        unsigned long flags;
-        in_cache_entry *entry;
-
-        read_lock_irqsave(&client->ingress_lock, flags);
-        entry = client->in_cache;
-        while(entry != NULL){
-                if((entry->ctrl_info.in_dst_ip & mask)  == (dst_ip & mask )){
-                        read_unlock_irqrestore(&client->ingress_lock, flags);
-                        return entry;
-                }
-                entry = entry->next;
-        }
-        read_unlock_irqrestore(&client->ingress_lock, flags);
-
-        return NULL;
-  
-}
-
-static in_cache_entry *in_cache_search_by_vcc(struct atm_vcc *vcc, 
-					      struct mpoa_client *client )
-{
-        unsigned long flags;
-        in_cache_entry *entry;
-
-        read_lock_irqsave(&client->ingress_lock, flags);
-        entry = client->in_cache;
-        while(entry != NULL){
-	        if(entry->shortcut == vcc) {
-                        read_unlock_irqrestore(&client->ingress_lock, flags);
-		        return entry;
-                }
+	read_lock_bh(&client->ingress_lock);
+	entry = client->in_cache;
+	while(entry != NULL){
+		if( entry->ctrl_info.in_dst_ip == dst_ip ){
+			atomic_inc(&entry->use);
+			read_unlock_bh(&client->ingress_lock);
+			return entry;
+		}
+		entry = entry->next;
+	}
+	read_unlock_bh(&client->ingress_lock);
+
+	return NULL;
+}
+
+static in_cache_entry *in_cache_get_with_mask(uint32_t dst_ip,
+					      struct mpoa_client *client,
+					      uint32_t mask)
+{
+	in_cache_entry *entry;
+
+	read_lock_bh(&client->ingress_lock);
+	entry = client->in_cache;
+	while(entry != NULL){
+		if((entry->ctrl_info.in_dst_ip & mask)  == (dst_ip & mask )){
+			atomic_inc(&entry->use);
+			read_unlock_bh(&client->ingress_lock);
+			return entry;
+		}
+		entry = entry->next;
+	}
+	read_unlock_bh(&client->ingress_lock);
+
+	return NULL;
+
+}
+
+static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc,
+					   struct mpoa_client *client )
+{
+	in_cache_entry *entry;
+
+	read_lock_bh(&client->ingress_lock);
+	entry = client->in_cache;
+	while(entry != NULL){
+		if(entry->shortcut == vcc) {
+			atomic_inc(&entry->use);
+			read_unlock_bh(&client->ingress_lock);
+			return entry;
+		}
 		entry = entry->next;
-        }
-        read_unlock_irqrestore(&client->ingress_lock, flags);
+	}
+	read_unlock_bh(&client->ingress_lock);
 
-        return NULL;
+	return NULL;
 }
 
-static in_cache_entry *new_in_cache_entry(uint32_t dst_ip, 
+static in_cache_entry *in_cache_add_entry(uint32_t dst_ip,
 					  struct mpoa_client *client)
 {
-        unsigned long flags;
-        unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
-        in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL);
-
-        if (entry == NULL) {
-                printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
-                return NULL;
-        }
-
-        dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
-        memset(entry,0,sizeof(in_cache_entry));
-
-        dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n");
-        write_lock_irqsave(&client->ingress_lock, flags);
-        entry->next = client->in_cache;
-        entry->prev = NULL;
-        if (client->in_cache != NULL)
-                client->in_cache->prev = entry;
-        client->in_cache = entry;
-        write_unlock_irqrestore(&client->ingress_lock, flags);
-        dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n");
-
-        memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
-        entry->ctrl_info.in_dst_ip = dst_ip;
-        do_gettimeofday(&(entry->tv));
-        entry->retry_time = client->parameters.mpc_p4;
-        entry->count = 1;
-        entry->entry_state = INGRESS_INVALID; 
-        entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT;
+	unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
+	in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL);
+
+	if (entry == NULL) {
+		printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
+		return NULL;
+	}
+
+	dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
+	memset(entry,0,sizeof(in_cache_entry));
+
+	atomic_set(&entry->use, 1);
+	dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n");
+	write_lock_bh(&client->ingress_lock);
+	entry->next = client->in_cache;
+	entry->prev = NULL;
+	if (client->in_cache != NULL)
+		client->in_cache->prev = entry;
+	client->in_cache = entry;
+
+	memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
+	entry->ctrl_info.in_dst_ip = dst_ip;
+	do_gettimeofday(&(entry->tv));
+	entry->retry_time = client->parameters.mpc_p4;
+	entry->count = 1;
+	entry->entry_state = INGRESS_INVALID;
+	entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT;
+	atomic_inc(&entry->use);
+
+	write_unlock_bh(&client->ingress_lock);
+	dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n");
 
 	return entry;
 }
 
-static int cache_hit( in_cache_entry * entry, struct mpoa_client *mpc)
+static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc)
 {
-        struct atm_mpoa_qos *qos;
-        struct k_message msg;
+	struct atm_mpoa_qos *qos;
+	struct k_message msg;
 
-        entry->count++;
+	entry->count++;
 	if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
-                return OPEN;
+		return OPEN;
 
 	if(entry->entry_state == INGRESS_REFRESHING){
-	        if(entry->count > mpc->parameters.mpc_p1){
-		        msg.type = SND_MPOA_RES_RQST;
+		if(entry->count > mpc->parameters.mpc_p1){
+			msg.type = SND_MPOA_RES_RQST;
 			msg.content.in_info = entry->ctrl_info;
 			memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
-                        qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
-                        if (qos != NULL) msg.qos = qos->qos;
+			qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
+			if (qos != NULL) msg.qos = qos->qos;
 			msg_to_mpoad(&msg, mpc);
 			do_gettimeofday(&(entry->reply_wait));
 			entry->entry_state = INGRESS_RESOLVING;
 		}
 		if(entry->shortcut != NULL)
-                        return OPEN;
+			return OPEN;
 		return CLOSED;
 	}
 
-        if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
-	        return OPEN;
+	if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
+		return OPEN;
 
-        if( entry->count > mpc->parameters.mpc_p1 &&
-            entry->entry_state == INGRESS_INVALID){
-                unsigned char *ip __attribute__ ((unused)) =
+	if( entry->count > mpc->parameters.mpc_p1 &&
+	    entry->entry_state == INGRESS_INVALID){
+		unsigned char *ip __attribute__ ((unused)) =
 		    (unsigned char *)&entry->ctrl_info.in_dst_ip;
 
 		dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
-                entry->entry_state = INGRESS_RESOLVING;
-                msg.type =  SND_MPOA_RES_RQST;
-                memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
-                msg.content.in_info = entry->ctrl_info;
-                qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
-                if (qos != NULL) msg.qos = qos->qos;
-                msg_to_mpoad( &msg, mpc);
-                do_gettimeofday(&(entry->reply_wait));
-        }
+		entry->entry_state = INGRESS_RESOLVING;
+		msg.type =  SND_MPOA_RES_RQST;
+		memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
+		msg.content.in_info = entry->ctrl_info;
+		qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
+		if (qos != NULL) msg.qos = qos->qos;
+		msg_to_mpoad( &msg, mpc);
+		do_gettimeofday(&(entry->reply_wait));
+	}
 
-        return CLOSED;
+	return CLOSED;
 }
 
-/*
- * If there are no more references to vcc in egress cache,
- * we are ready to close it.
- */
-static void close_unused_egress_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc)
+static void in_cache_put(in_cache_entry *entry)
 {
-	if (vcc == NULL)
-		return;
-
-	dprintk("mpoa: mpoa_caches.c: close_unused_egress_vcc:\n");
-        if (mpc->eg_ops->search_by_vcc(vcc, mpc) != NULL)
-                return;                             /* entry still in use */
-
-	atm_async_release_vcc(vcc, -EPIPE); /* nobody uses this VCC anymore, close it */
-	dprintk("mpoa: mpoa_caches.c: close_unused_egress_vcc, closed one:\n");
+	if (atomic_dec_and_test(&entry->use)) {
+		memset(entry, 0, sizeof(in_cache_entry));
+		kfree(entry);
+	}
 
 	return;
 }
@@ -188,371 +182,395 @@
 /*
  * This should be called with write lock on
  */
-static int in_cache_remove( in_cache_entry *entry,
-                            struct mpoa_client *client )
+static void in_cache_remove_entry(in_cache_entry *entry,
+				  struct mpoa_client *client)
 {
 	struct atm_vcc *vcc;
-        struct k_message msg;
-        unsigned char *ip;
-
-        if(entry == NULL)
-                return 0;
+	struct k_message msg;
+	unsigned char *ip;
 
 	vcc = entry->shortcut;
-        ip = (unsigned char *)&entry->ctrl_info.in_dst_ip;
-        dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",ip[0], ip[1], ip[2], ip[3]);
+	ip = (unsigned char *)&entry->ctrl_info.in_dst_ip;
+	dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",ip[0], ip[1], ip[2], ip[3]);
 
-        if (entry->prev != NULL)
-                entry->prev->next = entry->next;
-        else
-                client->in_cache = entry->next;
-        if (entry->next != NULL)
-                entry->next->prev = entry->prev;
-        memset(entry, 0, sizeof(in_cache_entry));
-        kfree(entry);
+	if (entry->prev != NULL)
+		entry->prev->next = entry->next;
+	else
+		client->in_cache = entry->next;
+	if (entry->next != NULL)
+		entry->next->prev = entry->prev;
+	client->in_ops->put(entry);
 	if(client->in_cache == NULL && client->eg_cache == NULL){
-	        msg.type = STOP_KEEP_ALIVE_SM;
+		msg.type = STOP_KEEP_ALIVE_SM;
 		msg_to_mpoad(&msg,client);
 	}
 
-	close_unused_egress_vcc(vcc, client);
-        return 1;
-} 
+	/* Check if the egress side still uses this VCC */
+	if (vcc != NULL) {
+		eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, client);
+		if (eg_entry != NULL) {
+			client->eg_ops->put(eg_entry);
+			return;
+		}
+		atm_async_release_vcc(vcc, -EPIPE);
+	}
+
+	return;
+}
 
 
-/* Call this every MPC-p2 seconds... Not exactly correct solution, 
+/* Call this every MPC-p2 seconds... Not exactly correct solution,
    but an easy one... */
-
 static void clear_count_and_expired(struct mpoa_client *client)
 {
-        unsigned char *ip;
-        unsigned long flags;
-        in_cache_entry *entry, *next_entry;
-        struct timeval now;
+	unsigned char *ip;
+	in_cache_entry *entry, *next_entry;
+	struct timeval now;
 
 	do_gettimeofday(&now);
-        
-        write_lock_irqsave(&client->ingress_lock, flags);
-        entry = client->in_cache;
-        while(entry != NULL){
-                entry->count=0;
-                next_entry = entry->next;
-                if((now.tv_sec - entry->tv.tv_sec) 
-                   > entry->ctrl_info.holding_time){
-		        ip = (unsigned char*)&entry->ctrl_info.in_dst_ip;
-		        dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
-                        in_cache_remove(entry, client);
-                }
-                entry = next_entry;
-        }
-        write_unlock_irqrestore(&client->ingress_lock, flags);
-
-        return;
-}
-
-/* Call this every MPC-p4 seconds. */ 
-
-static void check_resolving_entries( struct mpoa_client * client )
-{
-
-        struct atm_mpoa_qos *qos;
-        unsigned long flags;
-        in_cache_entry *entry;
-        struct timeval now;
-        struct k_message msg;
+
+	write_lock_bh(&client->ingress_lock);
+	entry = client->in_cache;
+	while(entry != NULL){
+		entry->count=0;
+		next_entry = entry->next;
+		if((now.tv_sec - entry->tv.tv_sec)
+		   > entry->ctrl_info.holding_time){
+			ip = (unsigned char*)&entry->ctrl_info.in_dst_ip;
+			dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(ip));
+			client->in_ops->remove_entry(entry, client);
+		}
+		entry = next_entry;
+	}
+	write_unlock_bh(&client->ingress_lock);
+
+	return;
+}
+
+/* Call this every MPC-p4 seconds. */
+static void check_resolving_entries(struct mpoa_client *client)
+{
+
+	struct atm_mpoa_qos *qos;
+	in_cache_entry *entry;
+	struct timeval now;
+	struct k_message msg;
 
 	do_gettimeofday( &now );
 
-        read_lock_irqsave(&client->ingress_lock, flags);
-        entry = client->in_cache;
-        while( entry != NULL ){
-                if(entry->entry_state == INGRESS_RESOLVING){
-                        if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){
-                                entry = entry->next;                      /* Entry in hold down */
-                                continue;
-                        }
-                        if( (now.tv_sec - entry->reply_wait.tv_sec) >
-                            entry->retry_time ){
-                                entry->retry_time = MPC_C1*( entry->retry_time );
-                                if(entry->retry_time > client->parameters.mpc_p5){
-				        /* Retry time maximum exceeded, put entry in hold down. */  
-				        do_gettimeofday(&(entry->hold_down)); 
-                                        entry->retry_time = client->parameters.mpc_p4; 
-                                        entry = entry->next;
-                                        continue;
-                                }
+	read_lock_bh(&client->ingress_lock);
+	entry = client->in_cache;
+	while( entry != NULL ){
+		if(entry->entry_state == INGRESS_RESOLVING){
+			if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){
+				entry = entry->next;                      /* Entry in hold down */
+				continue;
+			}
+			if( (now.tv_sec - entry->reply_wait.tv_sec) >
+			    entry->retry_time ){
+				entry->retry_time = MPC_C1*( entry->retry_time );
+				if(entry->retry_time > client->parameters.mpc_p5){
+					/* Retry time maximum exceeded, put entry in hold down. */
+					do_gettimeofday(&(entry->hold_down));
+					entry->retry_time = client->parameters.mpc_p4;
+					entry = entry->next;
+					continue;
+				}
 				/* Ask daemon to send a resolution request. */
-                                memset(&(entry->hold_down),0,sizeof(struct timeval));
-                                msg.type = SND_MPOA_RES_RTRY;
-                                memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN);
-                                msg.content.in_info = entry->ctrl_info;
-                                qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
-                                if (qos != NULL) msg.qos = qos->qos;
-                                msg_to_mpoad(&msg, client);
-                                do_gettimeofday(&(entry->reply_wait));
-                        }
-                }
-                entry = entry->next;
-        }
-        read_unlock_irqrestore(&client->ingress_lock, flags);
+				memset(&(entry->hold_down),0,sizeof(struct timeval));
+				msg.type = SND_MPOA_RES_RTRY;
+				memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN);
+				msg.content.in_info = entry->ctrl_info;
+				qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
+				if (qos != NULL) msg.qos = qos->qos;
+				msg_to_mpoad(&msg, client);
+				do_gettimeofday(&(entry->reply_wait));
+			}
+		}
+		entry = entry->next;
+	}
+	read_unlock_bh(&client->ingress_lock);
 }
 
 /* Call this every MPC-p5 seconds. */
-
-static void refresh_entries( struct mpoa_client * client )
+static void refresh_entries(struct mpoa_client *client)
 {
-        unsigned long flags;
-        struct timeval now;
-        struct in_cache_entry *entry = client->in_cache;
-        
-        ddprintk("mpoa: mpoa_caches.c: refresh_entries\n");
+	struct timeval now;
+	struct in_cache_entry *entry = client->in_cache;
+
+	ddprintk("mpoa: mpoa_caches.c: refresh_entries\n");
 	do_gettimeofday(&now);
 
-        read_lock_irqsave(&client->ingress_lock, flags);
-        while( entry != NULL ){
-                if( entry->entry_state == INGRESS_RESOLVED ){
-                        if(!(entry->refresh_time))
-			        entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3;
+	read_lock_bh(&client->ingress_lock);
+	while( entry != NULL ){
+		if( entry->entry_state == INGRESS_RESOLVED ){
+			if(!(entry->refresh_time))
+				entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3;
 			if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){
-                                dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n");
+				dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n");
 				entry->entry_state = INGRESS_REFRESHING;
-                                
+
 			}
-                }
-                entry = entry->next;
-        }
-        read_unlock_irqrestore(&client->ingress_lock, flags);
+		}
+		entry = entry->next;
+	}
+	read_unlock_bh(&client->ingress_lock);
 }
 
-static eg_cache_entry *eg_cache_search_by_cache_id(uint32_t cache_id,
-						  struct mpoa_client *client)
+static void in_destroy_cache(struct mpoa_client *mpc)
 {
-        eg_cache_entry *entry;
-        unsigned long flags;
-
-        read_lock_irqsave(&client->egress_lock, flags);
-        entry = client->eg_cache;
-        while(entry != NULL){
-                if( entry->ctrl_info.cache_id == cache_id){
-                        read_unlock_irqrestore(&client->egress_lock, flags);
-                        return entry;
-                }
-                entry = entry->next;
-        }
-	read_unlock_irqrestore(&client->egress_lock, flags);
+	write_lock_irq(&mpc->ingress_lock);
+	while(mpc->in_cache != NULL)
+		mpc->in_ops->remove_entry(mpc->in_cache, mpc);
+	write_unlock_irq(&mpc->ingress_lock);
 
-        return NULL;
+	return;
 }
 
-static eg_cache_entry *eg_cache_search_by_tag(uint32_t tag,
-					      struct mpoa_client *client)
+static eg_cache_entry *eg_cache_get_by_cache_id(uint32_t cache_id, struct mpoa_client *mpc)
 {
-        unsigned long flags;
-        eg_cache_entry *entry;
+	eg_cache_entry *entry;
 
-        read_lock_irqsave(&client->egress_lock, flags);
-        entry = client->eg_cache;
-        while(entry != NULL){
-                if( entry->ctrl_info.tag == tag){
-                        read_unlock_irqrestore(&client->egress_lock, flags);
-                        return entry;
-                }
-                entry = entry->next;
-        }
-	read_unlock_irqrestore(&client->egress_lock, flags);
+	read_lock_irq(&mpc->egress_lock);
+	entry = mpc->eg_cache;
+	while(entry != NULL){
+		if(entry->ctrl_info.cache_id == cache_id){
+			atomic_inc(&entry->use);
+			read_unlock_irq(&mpc->egress_lock);
+			return entry;
+		}
+		entry = entry->next;
+	}
+	read_unlock_irq(&mpc->egress_lock);
 
-        return NULL;
+	return NULL;
 }
 
-static eg_cache_entry *eg_cache_search_by_vcc(struct atm_vcc *vcc,
-                                               struct mpoa_client *client )
+/* This can be called from any context since it saves CPU flags */
+static eg_cache_entry *eg_cache_get_by_tag(uint32_t tag, struct mpoa_client *mpc)
 {
-        unsigned long flags;
-        eg_cache_entry *entry;
+	unsigned long flags;
+	eg_cache_entry *entry;
 
-        read_lock_irqsave(&client->egress_lock, flags);
-        entry = client->eg_cache;
-        while( entry != NULL ){
-                if( entry->shortcut == vcc ) {
-               	        read_unlock_irqrestore(&client->egress_lock, flags);
-                        return entry;
+	read_lock_irqsave(&mpc->egress_lock, flags);
+	entry = mpc->eg_cache;
+	while (entry != NULL){
+		if (entry->ctrl_info.tag == tag) {
+			atomic_inc(&entry->use);
+			read_unlock_irqrestore(&mpc->egress_lock, flags);
+			return entry;
 		}
-                entry = entry->next;
-        }
-	read_unlock_irqrestore(&client->egress_lock, flags);
+		entry = entry->next;
+	}
+	read_unlock_irqrestore(&mpc->egress_lock, flags);
 
-        return NULL;
+	return NULL;
 }
 
-static eg_cache_entry *eg_cache_search_by_src_ip(uint32_t ipaddr,
-						 struct mpoa_client *client)
+/* This can be called from any context since it saves CPU flags */
+static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc)
 {
-        unsigned long flags;
-        eg_cache_entry *entry;
+	unsigned long flags;
+	eg_cache_entry *entry;
 
-        read_lock_irqsave(&client->egress_lock, flags);
-        entry = client->eg_cache;
-        while( entry != NULL ){
-                if(entry->latest_ip_addr == ipaddr) {
-                        break;
+	read_lock_irqsave(&mpc->egress_lock, flags);
+	entry = mpc->eg_cache;
+	while (entry != NULL){
+		if (entry->shortcut == vcc) {
+			atomic_inc(&entry->use);
+	       		read_unlock_irqrestore(&mpc->egress_lock, flags);
+			return entry;
 		}
-                entry = entry->next;
-        }
-	read_unlock_irqrestore(&client->egress_lock, flags);
+		entry = entry->next;
+	}
+	read_unlock_irqrestore(&mpc->egress_lock, flags);
 
-        return entry;
+	return NULL;
 }
 
-/*
- * If there are no more references to vcc in ingress cache,
- * we are ready to close it.
- */
-static void close_unused_ingress_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc)
+static eg_cache_entry *eg_cache_get_by_src_ip(uint32_t ipaddr, struct mpoa_client *mpc)
 {
-	if (vcc == NULL)
-		return;
+	eg_cache_entry *entry;
 
-	dprintk("mpoa: mpoa_caches.c: close_unused_ingress_vcc:\n");
-        if (mpc->in_ops->search_by_vcc(vcc, mpc) != NULL)
-                return;                             /* entry still in use */
+	read_lock_irq(&mpc->egress_lock);
+	entry = mpc->eg_cache;
+	while(entry != NULL){
+		if(entry->latest_ip_addr == ipaddr) {
+			atomic_inc(&entry->use);
+	       		read_unlock_irq(&mpc->egress_lock);
+			return entry;
+		}
+		entry = entry->next;
+	}
+	read_unlock_irq(&mpc->egress_lock);
 
-	atm_async_release_vcc(vcc, -EPIPE); /* nobody uses this VCC anymore, close it */
-	dprintk("mpoa: mpoa_caches.c: close_unused_ingress_vcc:, closed one\n");
+	return NULL;
+}
+
+static void eg_cache_put(eg_cache_entry *entry)
+{
+	if (atomic_dec_and_test(&entry->use)) {
+		memset(entry, 0, sizeof(eg_cache_entry));
+		kfree(entry);
+	}
 
 	return;
 }
+
 /*
  * This should be called with write lock on
  */
-static int eg_cache_remove(eg_cache_entry *entry, 
-                           struct mpoa_client *client)
+static void eg_cache_remove_entry(eg_cache_entry *entry,
+				  struct mpoa_client *client)
 {
 	struct atm_vcc *vcc;
-        struct k_message msg; 
-        if(entry == NULL)
-                return 0;
+	struct k_message msg;
 
 	vcc = entry->shortcut;
-        dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n");
-        if (entry->prev != NULL)
-                entry->prev->next = entry->next;
-        else
-                client->eg_cache = entry->next;
-        if (entry->next != NULL)
-                entry->next->prev = entry->prev;
-        memset(entry, 0, sizeof(eg_cache_entry));
-        kfree(entry);
+	dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n");
+	if (entry->prev != NULL)
+		entry->prev->next = entry->next;
+	else
+		client->eg_cache = entry->next;
+	if (entry->next != NULL)
+		entry->next->prev = entry->prev;
+	client->eg_ops->put(entry);
 	if(client->in_cache == NULL && client->eg_cache == NULL){
-	        msg.type = STOP_KEEP_ALIVE_SM;
+		msg.type = STOP_KEEP_ALIVE_SM;
 		msg_to_mpoad(&msg,client);
 	}
 
-	close_unused_ingress_vcc(vcc, client);
+	/* Check if the ingress side still uses this VCC */
+	if (vcc != NULL) {
+		in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client);
+		if (in_entry != NULL) {
+			client->in_ops->put(in_entry);
+			return;
+		}
+		atm_async_release_vcc(vcc, -EPIPE);
+	}
 
-        return 1;
-} 
+	return;
+}
 
-static eg_cache_entry *new_eg_cache_entry(struct k_message *msg, struct mpoa_client *client)
+static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client)
 {
-        unsigned long flags;
-        unsigned char *ip;
-        eg_cache_entry *entry = kmalloc(sizeof(eg_cache_entry), GFP_KERNEL);
-
-        if (entry == NULL) {
-                printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n");
-                return NULL;
-	}
-
-        ip = (unsigned char *)&msg->content.eg_info.eg_dst_ip;
-        dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %d.%d.%d.%d, this should be our IP\n", ip[0], ip[1], ip[2], ip[3]);
-        memset(entry, 0, sizeof(eg_cache_entry));
-
-        dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n");
-        write_lock_irqsave(&client->egress_lock, flags);
-        entry->next = client->eg_cache;
-        entry->prev = NULL;
-        if (client->eg_cache != NULL)
-                client->eg_cache->prev = entry;
-        client->eg_cache = entry;
-        write_unlock_irqrestore(&client->egress_lock, flags);
-        dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n");
-
-        memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
-        entry->ctrl_info = msg->content.eg_info;
-        do_gettimeofday(&(entry->tv));
-        entry->entry_state = EGRESS_RESOLVED;
-        dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id));
-        ip = (unsigned char *)&entry->ctrl_info.mps_ip;
-        dprintk("mpoa: mpoa_caches.c: mps_ip = %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
-        return entry;
+	unsigned char *ip;
+	eg_cache_entry *entry = kmalloc(sizeof(eg_cache_entry), GFP_KERNEL);
+
+	if (entry == NULL) {
+		printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n");
+		return NULL;
+	}
+
+	ip = (unsigned char *)&msg->content.eg_info.eg_dst_ip;
+	dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(ip));
+	memset(entry, 0, sizeof(eg_cache_entry));
+
+	atomic_set(&entry->use, 1);
+	dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n");
+	write_lock_irq(&client->egress_lock);
+	entry->next = client->eg_cache;
+	entry->prev = NULL;
+	if (client->eg_cache != NULL)
+		client->eg_cache->prev = entry;
+	client->eg_cache = entry;
+
+	memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
+	entry->ctrl_info = msg->content.eg_info;
+	do_gettimeofday(&(entry->tv));
+	entry->entry_state = EGRESS_RESOLVED;
+	dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id));
+	ip = (unsigned char *)&entry->ctrl_info.mps_ip;
+	dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n", NIPQUAD(ip));
+	atomic_inc(&entry->use);
+
+	write_unlock_irq(&client->egress_lock);
+	dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n");
+
+	return entry;
 }
 
 static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time)
 {
-        do_gettimeofday(&(entry->tv));
-        entry->entry_state = EGRESS_RESOLVED;
-        entry->ctrl_info.holding_time = holding_time;
+	do_gettimeofday(&(entry->tv));
+	entry->entry_state = EGRESS_RESOLVED;
+	entry->ctrl_info.holding_time = holding_time;
 
-        return;
+	return;
 }
 
-static void clear_expired(struct mpoa_client *client){
-        eg_cache_entry *entry, *next_entry;
-        unsigned long flags;
-        struct timeval now;
+static void clear_expired(struct mpoa_client *client)
+{
+	eg_cache_entry *entry, *next_entry;
+	struct timeval now;
 	struct k_message msg;
 
-        do_gettimeofday(&now);
+	do_gettimeofday(&now);
 
-        write_lock_irqsave(&client->egress_lock, flags);
-        entry = client->eg_cache;
-        while(entry != NULL){
-	        next_entry = entry->next;
-                if((now.tv_sec - entry->tv.tv_sec) 
-                   > entry->ctrl_info.holding_time){
-		        msg.type = SND_EGRESS_PURGE;
+	write_lock_irq(&client->egress_lock);
+	entry = client->eg_cache;
+	while(entry != NULL){
+		next_entry = entry->next;
+		if((now.tv_sec - entry->tv.tv_sec)
+		   > entry->ctrl_info.holding_time){
+			msg.type = SND_EGRESS_PURGE;
 			msg.content.eg_info = entry->ctrl_info;
-		        dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id));
+			dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id));
 			msg_to_mpoad(&msg, client);
-                        eg_cache_remove(entry, client);
-                }
-                entry = next_entry;
-        }
-        write_unlock_irqrestore(&client->egress_lock, flags);
+			client->eg_ops->remove_entry(entry, client);
+		}
+		entry = next_entry;
+	}
+	write_unlock_irq(&client->egress_lock);
+
+	return;
+}
+
+static void eg_destroy_cache(struct mpoa_client *mpc)
+{
+	write_lock_irq(&mpc->egress_lock);
+	while(mpc->eg_cache != NULL)
+		mpc->eg_ops->remove_entry(mpc->eg_cache, mpc);
+	write_unlock_irq(&mpc->egress_lock);
 
-        return;
+	return;
 }
 
 
 
 static struct in_cache_ops ingress_ops = {
-        new_in_cache_entry,               /* new_entry        */
-        in_cache_search,                  /* search           */
-        in_cache_search_with_mask,        /* search_with_mask */
-	in_cache_search_by_vcc,           /* search_by_vcc    */
-        cache_hit,                        /* cache_hit        */
-        in_cache_remove,                  /* cache_remove     */
-        clear_count_and_expired,          /* clear_count      */
-        check_resolving_entries,          /* check_resolving  */
-        refresh_entries,                  /* refresh          */
+	in_cache_add_entry,               /* add_entry       */
+	in_cache_get,                     /* get             */
+	in_cache_get_with_mask,           /* get_with_mask   */
+	in_cache_get_by_vcc,              /* get_by_vcc      */
+	in_cache_put,                     /* put             */
+	in_cache_remove_entry,            /* remove_entry    */
+	cache_hit,                        /* cache_hit       */
+	clear_count_and_expired,          /* clear_count     */
+	check_resolving_entries,          /* check_resolving */
+	refresh_entries,                  /* refresh         */
+	in_destroy_cache                  /* destroy_cache   */
 };
 
 static struct eg_cache_ops egress_ops = {
-        new_eg_cache_entry,               /* new_entry          */
-        eg_cache_search_by_cache_id,      /* search_by_cache_id */
-        eg_cache_search_by_tag,           /* search_by_tag      */ 
-        eg_cache_search_by_vcc,           /* search_by_vcc      */
-        eg_cache_search_by_src_ip,        /* search_by_src_ip   */
-        eg_cache_remove,                  /* cache_remove       */
-        update_eg_cache_entry,            /* update             */
-	clear_expired                     /* clear_expired      */
+	eg_cache_add_entry,               /* add_entry        */
+	eg_cache_get_by_cache_id,         /* get_by_cache_id  */
+	eg_cache_get_by_tag,              /* get_by_tag       */
+	eg_cache_get_by_vcc,              /* get_by_vcc       */
+	eg_cache_get_by_src_ip,           /* get_by_src_ip    */
+	eg_cache_put,                     /* put              */
+	eg_cache_remove_entry,            /* remove_entry     */
+	update_eg_cache_entry,            /* update           */
+	clear_expired,                    /* clear_expired    */
+	eg_destroy_cache                  /* destroy_cache    */
 };
 
 
 void atm_mpoa_init_cache(struct mpoa_client *mpc)
 {
-        mpc->in_ops = &ingress_ops;
-        mpc->eg_ops = &egress_ops;
+	mpc->in_ops = &ingress_ops;
+	mpc->eg_ops = &egress_ops;
 
-        return;
+	return;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/mpoa_caches.h linux/net/atm/mpoa_caches.h
--- v2.3.99-pre5/linux/net/atm/mpoa_caches.h	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/mpoa_caches.h	Fri Apr 14 09:37:20 2000
@@ -25,24 +25,27 @@
         struct   atm_vcc *shortcut;
         uint8_t  MPS_ctrl_ATM_addr[ATM_ESA_LEN];
         struct   in_ctrl_info ctrl_info;
+        atomic_t use;
 } in_cache_entry;
 
 struct in_cache_ops{
-        in_cache_entry *(*new_entry)(uint32_t dst_ip,
-				     struct mpoa_client *client);
-        in_cache_entry *(*search)(uint32_t dst_ip, struct mpoa_client *client);
-        in_cache_entry *(*search_with_mask)(uint32_t dst_ip, 
-					    struct mpoa_client *client,
-					    uint32_t mask);
-        in_cache_entry *(*search_by_vcc)(struct atm_vcc *vcc, 
-                                         struct mpoa_client *client);
-        int            (*cache_hit)(in_cache_entry *entry,
-                                    struct mpoa_client *client);
-        int            (*cache_remove)(in_cache_entry *delEntry,
-                                        struct mpoa_client *client );
-        void           (*clear_count)(struct mpoa_client *client);
-        void           (*check_resolving)(struct mpoa_client *client);
-        void           (*refresh)(struct mpoa_client *client);
+        in_cache_entry *(*add_entry)(uint32_t dst_ip,
+                                      struct mpoa_client *client);
+        in_cache_entry *(*get)(uint32_t dst_ip, struct mpoa_client *client);
+        in_cache_entry *(*get_with_mask)(uint32_t dst_ip, 
+					 struct mpoa_client *client,
+					 uint32_t mask);
+        in_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, 
+                                      struct mpoa_client *client);
+        void            (*put)(in_cache_entry *entry);
+        void            (*remove_entry)(in_cache_entry *delEntry,
+					struct mpoa_client *client );
+        int             (*cache_hit)(in_cache_entry *entry,
+                                     struct mpoa_client *client);
+        void            (*clear_count)(struct mpoa_client *client);
+        void            (*check_resolving)(struct mpoa_client *client);
+        void            (*refresh)(struct mpoa_client *client);
+        void            (*destroy_cache)(struct mpoa_client *mpc);
 };
 
 typedef struct eg_cache_entry{
@@ -55,17 +58,20 @@
         uint16_t             entry_state;
         uint32_t             latest_ip_addr;    /* The src IP address of the last packet */
         struct eg_ctrl_info  ctrl_info;
+        atomic_t             use;
 } eg_cache_entry;
 
 struct eg_cache_ops{
-        eg_cache_entry *(*new_entry)(struct k_message *msg, struct mpoa_client *client);
-        eg_cache_entry *(*search_by_cache_id)(uint32_t cache_id, struct mpoa_client *client);
-        eg_cache_entry *(*search_by_tag)(uint32_t cache_id, struct mpoa_client *client);
-        eg_cache_entry *(*search_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client);
-        eg_cache_entry *(*search_by_src_ip)(uint32_t ipaddr, struct mpoa_client *client);
-        int            (*cache_remove)(eg_cache_entry *entry, struct mpoa_client *client);
-        void           (*update)(eg_cache_entry *entry, uint16_t holding_time);
-        void           (*clear_expired)(struct mpoa_client *client);
+        eg_cache_entry *(*add_entry)(struct k_message *msg, struct mpoa_client *client);
+        eg_cache_entry *(*get_by_cache_id)(uint32_t cache_id, struct mpoa_client *client);
+        eg_cache_entry *(*get_by_tag)(uint32_t cache_id, struct mpoa_client *client);
+        eg_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client);
+        eg_cache_entry *(*get_by_src_ip)(uint32_t ipaddr, struct mpoa_client *client);
+        void            (*put)(eg_cache_entry *entry);
+        void            (*remove_entry)(eg_cache_entry *entry, struct mpoa_client *client);
+        void            (*update)(eg_cache_entry *entry, uint16_t holding_time);
+        void            (*clear_expired)(struct mpoa_client *client);
+        void            (*destroy_cache)(struct mpoa_client *mpc);
 };
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/pvc.c linux/net/atm/pvc.c
--- v2.3.99-pre5/linux/net/atm/pvc.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/pvc.c	Mon Apr 24 13:43:04 2000
@@ -78,23 +78,23 @@
 
 
 static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = {
-	PF_ATMPVC,
-	atm_release,
-	pvc_bind,
-	pvc_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	pvc_getname,
-	atm_poll,
-	atm_ioctl,
-	sock_no_listen,
-	pvc_shutdown,
-	atm_setsockopt,
-	atm_getsockopt,
-	sock_no_fcntl,
-	atm_sendmsg,
-	atm_recvmsg,
-	sock_no_mmap
+	family:		PF_ATMPVC,
+
+	release:	atm_release,
+	bind:		pvc_bind,
+	connect:	pvc_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	pvc_getname,
+	poll:		atm_poll,
+	ioctl:		atm_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	pvc_shutdown,
+	setsockopt:	atm_setsockopt,
+	getsockopt:	atm_getsockopt,
+	sendmsg:	atm_sendmsg,
+	recvmsg:	atm_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/raw.c linux/net/atm/raw.c
--- v2.3.99-pre5/linux/net/atm/raw.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/raw.c	Fri Apr 14 09:37:20 2000
@@ -39,7 +39,7 @@
 	DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
 	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
 	dev_kfree_skb_any(skb);
-	wake_up(&vcc->wsleep);
+	wake_up(&vcc->sleep);
 }
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/atm/svc.c linux/net/atm/svc.c
--- v2.3.99-pre5/linux/net/atm/svc.c	Mon Mar 27 08:08:33 2000
+++ linux/net/atm/svc.c	Mon Apr 24 13:43:04 2000
@@ -397,23 +397,23 @@
 
 
 static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = {
-	PF_ATMSVC,
-	svc_release,
-	svc_bind,
-	svc_connect,
-	sock_no_socketpair,
-	svc_accept,
-	svc_getname,
-	atm_poll,
-	atm_ioctl,
-	svc_listen,
-	svc_shutdown,
-	svc_setsockopt,
-	svc_getsockopt,
-	sock_no_fcntl,
-	atm_sendmsg,
-	atm_recvmsg,
-	sock_no_mmap
+	family:		PF_ATMSVC,
+
+	release:	svc_release,
+	bind:		svc_bind,
+	connect:	svc_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		svc_accept,
+	getname:	svc_getname,
+	poll:		atm_poll,
+	ioctl:		atm_ioctl,
+	listen:		svc_listen,
+	shutdown:	svc_shutdown,
+	setsockopt:	svc_setsockopt,
+	getsockopt:	svc_getsockopt,
+	sendmsg:	atm_sendmsg,
+	recvmsg:	atm_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.3.99-pre5/linux/net/ax25/af_ax25.c	Tue Mar 14 19:10:40 2000
+++ linux/net/ax25/af_ax25.c	Mon Apr 24 13:43:04 2000
@@ -1795,24 +1795,23 @@
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
-	PF_AX25,
+	family:		PF_AX25,
 
-	ax25_release,
-	ax25_bind,
-	ax25_connect,
-	sock_no_socketpair,
-	ax25_accept,
-	ax25_getname,
-	datagram_poll,
-	ax25_ioctl,
-	ax25_listen,
-	ax25_shutdown,
-	ax25_setsockopt,
-	ax25_getsockopt,
-	sock_no_fcntl,
-	ax25_sendmsg,
-	ax25_recvmsg,
-	sock_no_mmap
+	release:	ax25_release,
+	bind:		ax25_bind,
+	connect:	ax25_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		ax25_accept,
+	getname:	ax25_getname,
+	poll:		datagram_poll,
+	ioctl:		ax25_ioctl,
+	listen:		ax25_listen,
+	shutdown:	ax25_shutdown,
+	setsockopt:	ax25_setsockopt,
+	getsockopt:	ax25_getsockopt,
+	sendmsg:	ax25_sendmsg,
+	recvmsg:	ax25_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.3.99-pre5/linux/net/bridge/br.c	Tue Apr 11 15:09:26 2000
+++ linux/net/bridge/br.c	Fri Apr 14 09:37:20 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br.c,v 1.41 2000/03/24 01:33:36 davem Exp $
+ *	$Id: br.c,v 1.42 2000/04/14 10:10:34 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -45,10 +45,8 @@
 	br_handle_frame_hook = br_handle_frame;
 	br_ioctl_hook = br_ioctl_deviceless_stub;
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
-	write_lock(&lane_bridge_hook_lock);
 	br_fdb_get_hook = br_fdb_get;
 	br_fdb_put_hook = br_fdb_put;
-	write_unlock(&lane_bridge_hook_lock);
 #endif
 	register_netdevice_notifier(&br_device_notifier);
 
@@ -71,10 +69,8 @@
 	br_call_ioctl_atomic(__br_clear_ioctl_hook);
 	net_call_rx_atomic(__br_clear_frame_hook);
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
-	write_lock(&lane_bridge_hook_lock);
 	br_fdb_get_hook = NULL;
 	br_fdb_put_hook = NULL;
-	write_unlock(&lane_bridge_hook_lock);
 #endif
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/core/dev.c linux/net/core/dev.c
--- v2.3.99-pre5/linux/net/core/dev.c	Tue Apr 11 15:09:26 2000
+++ linux/net/core/dev.c	Mon Apr 24 13:59:56 2000
@@ -181,7 +181,7 @@
  *	dev_add_pack - add packet handler
  *	@pt: packet type declaration
  * 
- *	Add a protocol handler to the networking stack. The passed packet_type
+ *	Add a protocol handler to the networking stack. The passed &packet_type
  *	is linked into kernel lists and may not be freed until it has been
  *	removed from the kernel lists.
  */
@@ -217,7 +217,7 @@
  *	@pt: packet type declaration
  * 
  *	Remove a protocol handler that was previously added to the kernel
- *	protocol handlers by dev_add_pack. The passed packet_type is removed
+ *	protocol handlers by dev_add_pack(). The passed &packet_type is removed
  *	from the kernel lists and can be freed or reused once this function
  *	returns.
  */
@@ -260,9 +260,9 @@
  *	__dev_get_by_name	- find a device by its name 
  *	@name: name to find
  *
- *	Find an interface by name. Must be called under rtnl semaphore
- *	or dev_base_lock. If the name is found a pointer to the device
- *	is returned. If the name is not found then NULL is returned. The
+ *	Find an interface by name. Must be called under RTNL semaphore
+ *	or @dev_base_lock. If the name is found a pointer to the device
+ *	is returned. If the name is not found then %NULL is returned. The
  *	reference counters are not incremented so the caller must be
  *	careful with locks.
  */
@@ -286,7 +286,7 @@
  *	Find an interface by name. This can be called from any 
  *	context and does its own locking. The returned handle has
  *	the usage count incremented and the caller must use dev_put() to
- *	release it when it is no longer needed. NULL is returned if no
+ *	release it when it is no longer needed. %NULL is returned if no
  *	matching device is found.
  */
 
@@ -336,11 +336,11 @@
  *	__dev_get_by_index - find a device by its ifindex
  *	@ifindex: index of device
  *
- *	Search for an interface by index. Returns NULL if the device
+ *	Search for an interface by index. Returns %NULL if the device
  *	is not found or a pointer to the device. The device has not
  *	had its reference counter increased so the caller must be careful
- *	about locking. The caller must hold either the rtnl semaphore
- *	or dev_base_lock.
+ *	about locking. The caller must hold either the RTNL semaphore
+ *	or @dev_base_lock.
  */
 
 struct net_device * __dev_get_by_index(int ifindex)
@@ -440,15 +440,15 @@
  *	@name: name format string
  *	@err: error return pointer
  *
- *	Passed a format string - eg "lt%d" it will allocate a network device
- *	and space for the name. NULL is returned if no memory is available.
+ *	Passed a format string, eg. "lt%d", it will allocate a network device
+ *	and space for the name. %NULL is returned if no memory is available.
  *	If the allocation succeeds then the name is assigned and the 
- *	device pointer returned. NULL is returned if the name allocation failed.
- *	The cause of an error is returned as a negative errno code in the 
- *	variable err points to.
+ *	device pointer returned. %NULL is returned if the name allocation
+ *	failed. The cause of an error is returned as a negative errno code
+ *	in the variable @err points to.
  *
- *	The claler must hold the dev_base or rtnl locks when doing this in order
- *	to avoid duplicate name allocations.
+ *	The caller must hold the @dev_base or RTNL locks when doing this in
+ *	order to avoid duplicate name allocations.
  */
 
 struct net_device *dev_alloc(const char *name, int *err)
@@ -520,9 +520,9 @@
  *	dev_open	- prepare an interface for use. 
  *	@dev:	device to open
  *
- *	Takes a device from down to up state. The devices private open
+ *	Takes a device from down to up state. The device's private open
  *	function is invoked and then the multicast lists are loaded. Finally
- *	the device is moved into the up state and a NETDEV_UP message is
+ *	the device is moved into the up state and a %NETDEV_UP message is
  *	sent to the netdev notifier chain.
  *
  *	Calling this function on an active interface is a nop. On a failure
@@ -622,8 +622,8 @@
  *	@dev: device to shutdown
  *
  *	This function moves an active device into down state. A 
- *	NETDEV_GOING_DOWN is sent to the netev notifier chain. The device
- *	is then deactivated and finally a NETDEV_DOWN is sent to the notifier
+ *	%NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device
+ *	is then deactivated and finally a %NETDEV_DOWN is sent to the notifier
  *	chain.
  */
  
@@ -695,9 +695,10 @@
  *	unregister_netdevice_notifier - unregister a network notifier block
  *	@nb: notifier
  *
- *	Unregister a notifier previously registered by register_netdevice_notifier
- *	The notifier is unlinked into the kernel structures and may
- *	then be reused. A negative errno code is returned on a failure.
+ *	Unregister a notifier previously registered by
+ *	register_netdevice_notifier(). The notifier is unlinked into the
+ *	kernel structures and may then be reused. A negative errno code
+ *	is returned on a failure.
  */
 
 int unregister_netdevice_notifier(struct notifier_block *nb)
@@ -1079,7 +1080,7 @@
  *	@fn: function to call
  *
  *	Make a function call that is atomic with respect to the protocol
- *	layers
+ *	layers.
  */
  
 void net_call_rx_atomic(void (*fn)(void))
@@ -1426,10 +1427,11 @@
 static int dev_proc_stats(char *buffer, char **start, off_t offset,
 			  int length, int *eof, void *data)
 {
-	int i;
+	int i, lcpu;
 	int len=0;
 
-	for (i=0; i<smp_num_cpus; i++) {
+	for (lcpu=0; lcpu<smp_num_cpus; lcpu++) {
+		i = cpu_logical_map(lcpu);
 		len += sprintf(buffer+len, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
 			       netdev_rx_stat[i].total,
 			       netdev_rx_stat[i].dropped,
@@ -1554,10 +1556,10 @@
  *	@slave: slave device
  *	@master: new master device
  *
- *	Changes the master device of the slave. Pass NULL to break the
+ *	Changes the master device of the slave. Pass %NULL to break the
  *	bonding. The caller must hold the RTNL semaphore. On a failure
  *	a negative errno code is returned. On success the reference counts
- *	are adjusted, RTM_NEWLINK is sent to the routing socket and the
+ *	are adjusted, %RTM_NEWLINK is sent to the routing socket and the
  *	function returns zero.
  */
  
@@ -1629,7 +1631,7 @@
  *	Add or remove reception of all multicast frames to a device. While the
  *	count in the device remains above zero the interface remains listening
  *	to all interfaces. Once it hits zero the device reverts back to normal
- *	filtering operation. A negative inc value is used to drop the counter
+ *	filtering operation. A negative @inc value is used to drop the counter
  *	when releasing a resource needing all multicasts.
  */
 
@@ -2005,12 +2007,16 @@
 				return ret;
 			}
 #ifdef WIRELESS_EXT
+			/* Take care of Wireless Extensions */
 			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				dev_load(ifr.ifr_name);
-				if (IW_IS_SET(cmd)) {
-					if (!suser())
+				/* If command is `set a parameter', or
+				 * `get the encoding parameters', check if
+				 * the user has the right to do it */
+				if (IW_IS_SET(cmd) || (cmd == SIOCGIWENCODE)) {
+					if(!capable(CAP_NET_ADMIN))
 						return -EPERM;
 				}
+				dev_load(ifr.ifr_name);
 				rtnl_lock();
 				ret = dev_ifsioc(&ifr, cmd);
 				rtnl_unlock();
@@ -2051,7 +2057,7 @@
  *	@dev: device to register
  *	
  *	Take a completed network device structure and add it to the kernel
- *	interfaces. A NETDEV_REGISTER message is sent to the netdev notifier
+ *	interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier
  *	chain. 0 is returned on success. A negative errno code is returned
  *	on a failure to set up the device, or if the name is a duplicate.
  *
diff -u --recursive --new-file v2.3.99-pre5/linux/net/core/neighbour.c linux/net/core/neighbour.c
--- v2.3.99-pre5/linux/net/core/neighbour.c	Thu Feb 10 17:11:24 2000
+++ linux/net/core/neighbour.c	Fri Apr 21 16:08:45 2000
@@ -54,7 +54,7 @@
 static int neigh_glbl_allocs;
 static struct neigh_table *neigh_tables;
 
-#if defined(__i386__) && defined(__SMP__)
+#if defined(__i386__) && defined(CONFIG_SMP)
 #define ASSERT_WL(n) if ((int)((n)->lock.lock) > 0) { printk("WL assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
 #else
 #define ASSERT_WL(n) do { } while(0)
@@ -597,7 +597,7 @@
 	write_unlock(&tbl->lock);
 }
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static void neigh_periodic_timer(unsigned long arg)
 {
 	struct neigh_table *tbl = (struct neigh_table*)arg;
@@ -629,7 +629,7 @@
 	state = neigh->nud_state;
 
 	if (!(state&NUD_IN_TIMER)) {
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		printk("neigh: timer & !nud_in_timer\n");
 #endif
 		goto out;
@@ -1106,7 +1106,7 @@
 						     0, SLAB_HWCACHE_ALIGN,
 						     NULL, NULL);
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tasklet_init(&tbl->gc_task, SMP_TIMER_NAME(neigh_periodic_timer), (unsigned long)tbl);
 #endif
 	init_timer(&tbl->gc_timer);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/core/netfilter.c linux/net/core/netfilter.c
--- v2.3.99-pre5/linux/net/core/netfilter.c	Sun Mar 19 18:35:31 2000
+++ linux/net/core/netfilter.c	Thu Apr 13 17:19:57 2000
@@ -186,18 +186,10 @@
 			dst_port = ntohs(tcp->dest);
 		}
 	
-		printk("PROTO=%d %d.%d.%d.%d:%hu %d.%d.%d.%d:%hu"
+		printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
 		       " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
-		       ip->protocol,
-		       (ntohl(ip->saddr)>>24)&0xFF,
-		       (ntohl(ip->saddr)>>16)&0xFF,
-		       (ntohl(ip->saddr)>>8)&0xFF,
-		       (ntohl(ip->saddr))&0xFF,
-		       src_port,
-		       (ntohl(ip->daddr)>>24)&0xFF,
-		       (ntohl(ip->daddr)>>16)&0xFF,
-		       (ntohl(ip->daddr)>>8)&0xFF,
-		       (ntohl(ip->daddr))&0xFF,
+		       ip->protocol, NIPQUAD(ip->saddr),
+		       src_port, NIPQUAD(ip->daddr),
 		       dst_port,
 		       ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
 		       ntohs(ip->frag_off), ip->ttl);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.3.99-pre5/linux/net/core/skbuff.c	Tue Apr 11 15:09:26 2000
+++ linux/net/core/skbuff.c	Fri Apr 14 09:37:20 2000
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.71 2000/03/29 11:58:33 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.72 2000/04/13 00:55:54 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -83,7 +83,7 @@
  *	@sz: size
  *	@here: address
  *
- *	Out of line support code for skb_put. Not user callable
+ *	Out of line support code for skb_put(). Not user callable.
  */
  
 void skb_over_panic(struct sk_buff *skb, int sz, void *here)
@@ -99,7 +99,7 @@
  *	@sz: size
  *	@here: address
  *
- *	Out of line support code for skb_push. Not user callable
+ *	Out of line support code for skb_push(). Not user callable.
  */
  
 
@@ -154,12 +154,12 @@
  *	@size: size to allocate
  *	@gfp_mask: allocation mask
  *
- *	Allocate a new sk_buff. The returned buffer has no headroom and a
+ *	Allocate a new &sk_buff. The returned buffer has no headroom and a
  *	tail room of size bytes. The object has a reference count of one.
- *	The return is the buffer. On a failure the return is NULL.
+ *	The return is the buffer. On a failure the return is %NULL.
  *
- *	Buffers may only be allocated from interrupts using a gfp_mask of
- *	GFP_ATOMIC.
+ *	Buffers may only be allocated from interrupts using a @gfp_mask of
+ *	%GFP_ATOMIC.
  */
  
 struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
@@ -300,13 +300,13 @@
  *	@skb: buffer to clone
  *	@gfp_mask: allocation priority
  *
- *	Duplicate an sk_buff. The new one is not owned by a socket. Both
+ *	Duplicate an &sk_buff. The new one is not owned by a socket. Both
  *	copies share the same packet data but not structure. The new
  *	buffer has a reference count of 1. If the allocation fails the 
- *	function returns NULL otherwise the new buffer is returned.
+ *	function returns %NULL otherwise the new buffer is returned.
  *	
- *	If this function is called from an interrupt gfp_mask must be
- *	GFP_ATOMIC.
+ *	If this function is called from an interrupt gfp_mask() must be
+ *	%GFP_ATOMIC.
  */
 
 struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
@@ -383,12 +383,12 @@
  *	@skb: buffer to copy
  *	@gfp_mask: allocation priority
  *
- *	Make a copy of both an sk_buff and its data. This is used when the
+ *	Make a copy of both an &sk_buff and its data. This is used when the
  *	caller wishes to modify the data and needs a private copy of the 
- *	data to alter. Returns NULL on failure or the pointer to the buffer
+ *	data to alter. Returns %NULL on failure or the pointer to the buffer
  *	on success. The returned buffer has a reference count of 1.
  *
- *	You must pass GFP_ATOMIC as the allocation priority if this function
+ *	You must pass %GFP_ATOMIC as the allocation priority if this function
  *	is called from an interrupt.
  */
  
@@ -423,15 +423,15 @@
  *	@newtailroom: new free bytes at tail
  *	@gfp_mask: allocation priority
  *
- *	Make a copy of both an sk_buff and its data and while doing so 
+ *	Make a copy of both an &sk_buff and its data and while doing so 
  *	allocate additional space.
  *
  *	This is used when the caller wishes to modify the data and needs a 
  *	private copy of the data to alter as well as more space for new fields.
- *	 Returns NULL on failure or the pointer to the buffer
+ *	Returns %NULL on failure or the pointer to the buffer
  *	on success. The returned buffer has a reference count of 1.
  *
- *	You must pass GFP_ATOMIC as the allocation priority if this function
+ *	You must pass %GFP_ATOMIC as the allocation priority if this function
  *	is called from an interrupt.
  */
  
diff -u --recursive --new-file v2.3.99-pre5/linux/net/core/sock.c linux/net/core/sock.c
--- v2.3.99-pre5/linux/net/core/sock.c	Tue Apr 11 15:09:26 2000
+++ linux/net/core/sock.c	Fri Apr 14 09:37:20 2000
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.91 2000/03/25 01:55:03 davem Exp $
+ * Version:	$Id: sock.c,v 1.93 2000/04/13 03:13:29 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -786,18 +786,22 @@
 		if (sk->shutdown&SEND_SHUTDOWN)
 			goto failure;
 
-		if (fallback) {
-			/* The buffer get won't block, or use the atomic queue.
-			 * It does produce annoying no free page messages still.
-			 */
-			skb = sock_wmalloc(sk, size, 0, GFP_BUFFER);
+		if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
+			if (fallback) {
+				/* The buffer get won't block, or use the atomic queue.
+			 	* It does produce annoying no free page messages still.
+			 	*/
+				skb = alloc_skb(size, GFP_BUFFER);
+				if (skb)
+					break;
+				try_size = fallback;
+			}
+			skb = alloc_skb(try_size, sk->allocation);
 			if (skb)
 				break;
-			try_size = fallback;
+			err = -ENOBUFS;
+			goto failure;
 		}
-		skb = sock_wmalloc(sk, try_size, 0, sk->allocation);
-		if (skb)
-			break;
 
 		/*
 		 *	This means we have too many buffers for this socket already.
@@ -813,6 +817,7 @@
 		timeo = sock_wait_for_wmem(sk, timeo);
 	}
 
+	skb_set_owner_w(skb, sk);
 	return skb;
 
 interrupted:
@@ -1063,7 +1068,7 @@
 	return -EOPNOTSUPP;
 }
 
-int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int flags,
+int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int len, int flags,
 		    struct scm_cookie *scm)
 {
 	return -EOPNOTSUPP;
@@ -1136,7 +1141,6 @@
 	skb_queue_head_init(&sk->write_queue);
 	skb_queue_head_init(&sk->error_queue);
 
-	spin_lock_init(&sk->timer_lock);
 	init_timer(&sk->timer);
 	
 	sk->allocation	=	GFP_KERNEL;
diff -u --recursive --new-file v2.3.99-pre5/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.3.99-pre5/linux/net/decnet/af_decnet.c	Tue Apr 11 15:09:26 2000
+++ linux/net/decnet/af_decnet.c	Mon Apr 24 13:43:04 2000
@@ -2032,24 +2032,23 @@
 };
 
 static struct proto_ops dn_proto_ops = {
-        AF_DECnet,
+	family:		AF_DECnet,
 
-	dn_release,
-	dn_bind,
-	dn_connect,
-	sock_no_socketpair,
-	dn_accept,
-	dn_getname,
-	dn_poll,
-	dn_ioctl,
-	dn_listen,
-	dn_shutdown,
-	dn_setsockopt,
-	dn_getsockopt,
-	sock_no_fcntl,
-        dn_sendmsg,
-	dn_recvmsg,
-	sock_no_mmap
+	release:	dn_release,
+	bind:		dn_bind,
+	connect:	dn_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		dn_accept,
+	getname:	dn_getname,
+	poll:		dn_poll,
+	ioctl:		dn_ioctl,
+	listen:		dn_listen,
+	shutdown:	dn_shutdown,
+	setsockopt:	dn_setsockopt,
+	getsockopt:	dn_getsockopt,
+	sendmsg:	dn_sendmsg,
+	recvmsg:	dn_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #ifdef CONFIG_SYSCTL
@@ -2091,7 +2090,7 @@
 	decnet_address = dn_htons(area << 10 | node);
 	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 
-	return 0;
+	return 1;
 }
 
 __setup("decnet=", decnet_setup);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/decnet/sysctl_net_decnet.c linux/net/decnet/sysctl_net_decnet.c
--- v2.3.99-pre5/linux/net/decnet/sysctl_net_decnet.c	Fri Mar 10 16:40:51 2000
+++ linux/net/decnet/sysctl_net_decnet.c	Mon Apr 24 13:59:56 2000
@@ -54,6 +54,22 @@
 #define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
 #define INVALID_END_CHAR(x) (ISNUM(x) || ISALPHA(x))
 
+static void strip_it(char *str)
+{
+	for(;;) {
+		switch(*str) {
+			case ' ':
+			case '\n':
+			case '\r':
+			case ':':
+				*str = 0;
+			case 0:
+				return;
+		}
+		str++;
+	}
+}
+
 /*
  * Simple routine to parse an ascii DECnet address
  * into a network order address.
@@ -159,8 +175,9 @@
 			return -EFAULT;
 
 		addr[len] = 0;
+		strip_it(addr);
 
-		if (parse_addr(&dnaddr, buffer))
+		if (parse_addr(&dnaddr, addr))
 			return -EINVAL;
 
 		dn_dev_devices_off();
@@ -257,8 +274,6 @@
 	}
 
 	if (write) {
-		int i;
-
 		if (*lenp > 16)
 			return -E2BIG;
 
@@ -266,9 +281,7 @@
 			return -EFAULT;
 
 		devname[*lenp] = 0;
-		for(i = 0; i < (*lenp); i++)
-			if (devname[i] == '\n')
-				devname[i] = 0;
+		strip_it(devname);
 
 		if ((dev = __dev_get_by_name(devname)) == NULL)
 			return -ENODEV;
diff -u --recursive --new-file v2.3.99-pre5/linux/net/econet/af_econet.c linux/net/econet/af_econet.c
--- v2.3.99-pre5/linux/net/econet/af_econet.c	Tue Mar 14 19:10:40 2000
+++ linux/net/econet/af_econet.c	Mon Apr 24 13:43:04 2000
@@ -705,24 +705,23 @@
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {
-	PF_ECONET,
+	family:		PF_ECONET,
 
-	econet_release,
-	econet_bind,
-	sock_no_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	econet_getname, 
-	datagram_poll,
-	econet_ioctl,
-	sock_no_listen,
-	sock_no_shutdown,
-	sock_no_setsockopt,
-	sock_no_getsockopt,
-	sock_no_fcntl,
-	econet_sendmsg,
-	econet_recvmsg,
-	sock_no_mmap
+	release:	econet_release,
+	bind:		econet_bind,
+	connect:	sock_no_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	econet_getname, 
+	poll:		datagram_poll,
+	ioctl:		econet_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	sock_no_setsockopt,
+	getsockopt:	sock_no_getsockopt,
+	sendmsg:	econet_sendmsg,
+	recvmsg:	econet_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
@@ -1131,7 +1130,7 @@
 #endif
 }
 
-int __init econet_proto_init(struct net_proto *pro)
+int __init econet_proto_init(void)
 {
 	extern void econet_sysctl_register(void);
 	sock_register(&econet_family_ops);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.99-pre5/linux/net/ipv4/af_inet.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/af_inet.c	Wed Apr 26 12:13:17 2000
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.109 2000/03/25 01:55:10 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.110 2000/04/25 04:13:34 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -893,45 +893,43 @@
 }
 
 struct proto_ops inet_stream_ops = {
-	PF_INET,
+	family:		PF_INET,
 
-	inet_release,
-	inet_bind,
-	inet_stream_connect,
-	sock_no_socketpair,
-	inet_accept,
-	inet_getname, 
-	tcp_poll,
-	inet_ioctl,
-	inet_listen,
-	inet_shutdown,
-	inet_setsockopt,
-	inet_getsockopt,
-	sock_no_fcntl,
-	inet_sendmsg,
-	inet_recvmsg,
-	sock_no_mmap
+	release:	inet_release,
+	bind:		inet_bind,
+	connect:	inet_stream_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		inet_accept,
+	getname:	inet_getname, 
+	poll:		tcp_poll,
+	ioctl:		inet_ioctl,
+	listen:		inet_listen,
+	shutdown:	inet_shutdown,
+	setsockopt:	inet_setsockopt,
+	getsockopt:	inet_getsockopt,
+	sendmsg:	inet_sendmsg,
+	recvmsg:	inet_recvmsg,
+	mmap:		sock_no_mmap
 };
 
 struct proto_ops inet_dgram_ops = {
-	PF_INET,
+	family:		PF_INET,
 
-	inet_release,
-	inet_bind,
-	inet_dgram_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	inet_getname, 
-	datagram_poll,
-	inet_ioctl,
-	sock_no_listen,
-	inet_shutdown,
-	inet_setsockopt,
-	inet_getsockopt,
-	sock_no_fcntl,
-	inet_sendmsg,
-	inet_recvmsg,
-	sock_no_mmap
+	release:	inet_release,
+	bind:		inet_bind,
+	connect:	inet_dgram_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	inet_getname, 
+	poll:		datagram_poll,
+	ioctl:		inet_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	inet_shutdown,
+	setsockopt:	inet_setsockopt,
+	getsockopt:	inet_getsockopt,
+	sendmsg:	inet_sendmsg,
+	recvmsg:	inet_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 struct net_proto_family inet_family_ops = {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.3.99-pre5/linux/net/ipv4/arp.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/arp.c	Wed Apr 26 12:13:17 2000
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.84 2000/01/18 08:24:14 davem Exp $
+ * Version:	$Id: arp.c,v 1.86 2000/04/26 09:36:36 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -1021,7 +1021,6 @@
 	char hbuffer[HBUFFERLEN];
 	int i,j,k;
 	const char hexbuf[] =  "0123456789ABCDEF";
-	char abuf[16];
 
 	size = sprintf(buffer,"IP address       HW type     Flags       HW address            Mask     Device\n");
 
@@ -1060,15 +1059,21 @@
 		}
 #endif
 
-			size = sprintf(buffer+len,
-				"%-17s0x%-10x0x%-10x%s",
-				in_ntoa2(*(u32*)n->primary_key, abuf),
-				hatype,
-				arp_state_to_flags(n), 
-				hbuffer);
-			size += sprintf(buffer+len+size,
-				 "     %-17s %s\n",
-				 "*", dev->name);
+			{
+				char tbuf[16];
+				sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key));
+
+				size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s",
+					tbuf,
+					hatype,
+					arp_state_to_flags(n), 
+					hbuffer);
+
+				size += sprintf(buffer+len+size,
+					 "     %-8s %s\n",
+					 "*", dev->name);
+			}
+
 			read_unlock(&n->lock);
 
 			len += size;
@@ -1091,8 +1096,8 @@
 			int hatype = dev ? dev->type : 0;
 
 			size = sprintf(buffer+len,
-				"%-17s0x%-10x0x%-10x%s",
-				in_ntoa2(*(u32*)n->key, abuf),
+				"%u.%u.%u.%u0x%-10x0x%-10x%s",
+				NIPQUAD(*(u32*)n->key),
 				hatype,
  				ATF_PUBL|ATF_PERM,
 				"00:00:00:00:00:00");
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
--- v2.3.99-pre5/linux/net/ipv4/fib_rules.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/fib_rules.c	Mon Apr 24 13:59:56 2000
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: policy rules.
  *
- * Version:	$Id: fib_rules.c,v 1.14 1999/08/31 07:03:29 davem Exp $
+ * Version:	$Id: fib_rules.c,v 1.15 2000/04/15 01:48:10 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -298,7 +298,8 @@
 	u32 daddr = key->dst;
 	u32 saddr = key->src;
 
-FRprintk("Lookup: %08x <- %08x ", key->dst, key->src);
+FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
+	NIPQUAD(key->dst), NIPQUAD(key->src));
 	read_lock(&fib_rules_lock);
 	for (r = fib_rules; r; r=r->r_next) {
 		if (((saddr^r->r_src) & r->r_srcmask) ||
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.3.99-pre5/linux/net/ipv4/icmp.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/icmp.c	Mon Apr 24 13:59:56 2000
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.67 2000/03/25 01:55:11 davem Exp $
+ *	Version: $Id: icmp.c,v 1.69 2000/04/15 01:48:10 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -521,9 +521,12 @@
 	}
 	if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
 		goto out;
-	ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
-		icmp_param->data_len+sizeof(struct icmphdr),
-		&ipc, rt, MSG_DONTWAIT);
+	if (icmpv4_xrlim_allow(rt, icmp_param->icmph.type, 
+			       icmp_param->icmph.code)) { 
+		ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
+			      icmp_param->data_len+sizeof(struct icmphdr),
+			      &ipc, rt, MSG_DONTWAIT);
+	}
 	ip_rt_put(rt);
 out:
 	icmp_xmit_unlock_bh();
@@ -720,7 +723,7 @@
 			case ICMP_FRAG_NEEDED:
 				if (ipv4_config.no_pmtu_disc) {
 					if (net_ratelimit())
-						printk(KERN_INFO "ICMP: %d.%d.%d.%d: fragmentation needed and DF set.\n",
+						printk(KERN_INFO "ICMP: %u.%u.%u.%u: fragmentation needed and DF set.\n",
 						       NIPQUAD(iph->daddr));
 				} else {
 					unsigned short new_mtu;
@@ -732,7 +735,7 @@
 				break;
 			case ICMP_SR_FAILED:
 				if (net_ratelimit())
-					printk(KERN_INFO "ICMP: %d.%d.%d.%d: Source Route Failed.\n", NIPQUAD(iph->daddr));
+					printk(KERN_INFO "ICMP: %u.%u.%u.%u: Source Route Failed.\n", NIPQUAD(iph->daddr));
 				break;
 			default:
 				break;
@@ -762,7 +765,7 @@
 		if (inet_addr_type(iph->daddr) == RTN_BROADCAST)
 		{
 			if (net_ratelimit())
-				printk(KERN_WARNING "%d.%d.%d.%d sent an invalid ICMP error to a broadcast.\n",
+				printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP error to a broadcast.\n",
 			       	NIPQUAD(skb->nh.iph->saddr));
 			return; 
 		}
@@ -983,9 +986,8 @@
 				break;
 		}
 		if (!ifa && net_ratelimit()) {
-			char b1[16], b2[16];
-			printk(KERN_INFO "Wrong address mask %s from %s/%s\n",
-			       in_ntoa2(mask, b1), in_ntoa2(rt->rt_src, b2), dev->name);
+			printk(KERN_INFO "Wrong address mask %u.%u.%u.%u from %s/%u.%u.%u.%u\n",
+			       NIPQUAD(mask), dev->name, NIPQUAD(rt->rt_src));
 		}
 	}
 	read_unlock(&in_dev->lock);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.3.99-pre5/linux/net/ipv4/ip_fragment.c	Thu Feb 10 17:11:24 2000
+++ linux/net/ipv4/ip_fragment.c	Mon Apr 24 13:59:56 2000
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.47 2000/02/09 21:11:33 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.49 2000/04/15 01:48:10 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -387,9 +387,14 @@
 	*/
 	skb->security = qp->fragments->skb->security;
 
+#ifdef CONFIG_NETFILTER
+	/* Connection association is same as fragment (if any). */
+	skb->nfct = qp->fragments->skb->nfct;
+	nf_conntrack_get(skb->nfct);
 #ifdef CONFIG_NETFILTER_DEBUG
 	skb->nf_debug = qp->fragments->skb->nf_debug;
 #endif
+#endif
 
 	/* Done with all fragments. Fixup the new IP header. */
 	iph = skb->nh.iph;
@@ -594,7 +599,7 @@
 	 */
 out_oversize:
 	if (net_ratelimit())
-		printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n",
+		printk(KERN_INFO "Oversized packet received from %u.%u.%u.%u\n",
 			NIPQUAD(iph->saddr));
 	/* the skb isn't in a fragment, so fall through to free it */
 out_freeskb:
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.3.99-pre5/linux/net/ipv4/ip_input.c	Thu Mar  2 14:36:23 2000
+++ linux/net/ipv4/ip_input.c	Mon Apr 24 13:59:56 2000
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.46 2000/02/22 23:54:26 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.48 2000/04/15 01:48:10 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -162,7 +162,13 @@
 	read_lock(&ip_ra_lock);
 	for (ra = ip_ra_chain; ra; ra = ra->next) {
 		struct sock *sk = ra->sk;
-		if (sk && sk->num == protocol) {
+
+		/* If socket is bound to an interface, only report
+		 * the packet if it came  from that interface.
+		 */
+		if (sk && sk->num == protocol 
+		    && ((sk->bound_dev_if == 0) 
+			|| (sk->bound_dev_if == skb->dev->ifindex))) {
 			if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
 				skb = ip_defrag(skb);
 				if (skb == NULL) {
@@ -349,7 +355,7 @@
 			if (in_dev) {
 				if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
 					if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
-						printk(KERN_INFO "source route option %d.%d.%d.%d -> %d.%d.%d.%d\n",
+						printk(KERN_INFO "source route option %u.%u.%u.%u -> %u.%u.%u.%u\n",
 						       NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
 					in_dev_put(in_dev);
 					goto drop;
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.3.99-pre5/linux/net/ipv4/ipconfig.c	Sat Feb 26 22:32:08 2000
+++ linux/net/ipv4/ipconfig.c	Mon Apr 24 13:59:56 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.27 2000/02/21 15:51:41 davem Exp $
+ *  $Id: ipconfig.c,v 1.30 2000/04/15 01:48:10 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -77,7 +77,7 @@
 
 #define CONFIG_IP_PNP_DYNAMIC
 
-static int ic_proto_enabled __initdata = 0			/* Protocols enabled */
+int ic_proto_enabled __initdata = 0			/* Protocols enabled */
 #ifdef CONFIG_IP_PNP_BOOTP
 			| IC_BOOTP
 #endif
@@ -227,17 +227,20 @@
 	strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name);
 	set_sockaddr(sin, ic_myaddr, 0);
 	if ((err = ic_dev_ioctl(SIOCSIFADDR, &ir)) < 0) {
-		printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err);
+		printk(KERN_ERR "IP-Config: Unable to set interface address (%u.%u.%u.%u).\n",
+			NIPQUAD(err));
 		return -1;
 	}
 	set_sockaddr(sin, ic_netmask, 0);
 	if ((err = ic_dev_ioctl(SIOCSIFNETMASK, &ir)) < 0) {
-		printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err);
+		printk(KERN_ERR "IP-Config: Unable to set interface netmask (%u.%u.%u.%u).\n",
+			NIPQUAD(err));
 		return -1;
 	}
 	set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0);
 	if ((err = ic_dev_ioctl(SIOCSIFBRDADDR, &ir)) < 0) {
-		printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err);
+		printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%u.%u.%u.%u).\n",
+			NIPQUAD(err));
 		return -1;
 	}
 	return 0;
@@ -261,7 +264,8 @@
 		set_sockaddr((struct sockaddr_in *) &rm.rt_gateway, ic_gateway, 0);
 		rm.rt_flags = RTF_UP | RTF_GATEWAY;
 		if ((err = ic_route_ioctl(SIOCADDRT, &rm)) < 0) {
-			printk(KERN_ERR "IP-Config: Cannot add default route (%d).\n", err);
+			printk(KERN_ERR "IP-Config: Cannot add default route (%u.%u.%u.%u).\n",
+				NIPQUAD(err));
 			return -1;
 		}
 	}
@@ -294,10 +298,11 @@
 		else if (IN_CLASSC(ntohl(ic_myaddr)))
 			ic_netmask = htonl(IN_CLASSC_NET);
 		else {
-			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr);
+			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %u.%u.%u.%u\n",
+				NIPQUAD(ic_myaddr));
 			return -1;
 		}
-		printk("IP-Config: Guessing netmask %s\n", in_ntoa(ic_netmask));
+		printk("IP-Config: Guessing netmask %u.%u.%u.%u\n", NIPQUAD(ic_netmask));
 	}
 
 	return 0;
@@ -807,10 +812,10 @@
 	if (!ic_got_reply)
 		return -1;
 
-	printk("IP-Config: Got %s answer from %s, ",
+	printk("IP-Config: Got %s answer from %u.%u.%u.%u, ",
 		(ic_got_reply & IC_BOOTP) ? "BOOTP" : "RARP",
-		in_ntoa(ic_servaddr));
-	printk("my address is %s\n", in_ntoa(ic_myaddr));
+		NIPQUAD(ic_servaddr));
+	printk("my address is %u.%u.%u.%u\n", NIPQUAD(ic_myaddr));
 
 	return 0;
 }
@@ -986,7 +991,7 @@
 		num++;
 	}
 
-	return 0;
+	return 1;
 }
 
 static int __init nfsaddrs_config_setup(char *addrs)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_core.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_core.c	Thu Apr 13 17:15:54 2000
@@ -343,6 +343,7 @@
 	size_t hash, repl_hash;
 	struct ip_conntrack_expect *expected;
 	enum ip_conntrack_info ctinfo;
+	unsigned long extra_jiffies;
 	int i;
 
 	if (!invert_tuple(&repl_tuple, tuple, protocol)) {
@@ -366,19 +367,24 @@
 	repl_hash = hash_conntrack(&repl_tuple);
 
 	memset(conntrack, 0, sizeof(struct ip_conntrack));
-	atomic_set(&conntrack->ct_general.use, 1);
+	atomic_set(&conntrack->ct_general.use, 2);
 	conntrack->ct_general.destroy = destroy_conntrack;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
 	conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
-	for(i=0; i < IP_CT_NUMBER; i++)
+	for (i=0; i < IP_CT_NUMBER; i++)
 		conntrack->infos[i].master = &conntrack->ct_general;
 
-	if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
+	extra_jiffies = protocol->new(conntrack, skb->nh.iph, skb->len);
+	if (!extra_jiffies) {
 		kmem_cache_free(ip_conntrack_cachep, conntrack);
 		return 1;
 	}
+	conntrack->timeout.data = (unsigned long)conntrack;
+	conntrack->timeout.function = death_by_timeout;
+	conntrack->timeout.expires = jiffies + extra_jiffies;
+	add_timer(&conntrack->timeout);
 
 	/* Sew in at head of hash list. */
 	WRITE_LOCK(&ip_conntrack_lock);
@@ -421,7 +427,7 @@
 }
 
 static void
-resolve_normal_ct(struct sk_buff *skb)
+resolve_normal_ct(struct sk_buff *skb, int create)
 {
 	struct ip_conntrack_tuple tuple;
 	struct ip_conntrack_tuple_hash *h;
@@ -436,7 +442,7 @@
 	do {
 		/* look for tuple match */
 		h = ip_conntrack_find_get(&tuple, NULL);
-		if (!h && init_conntrack(&tuple, proto, skb))
+		if (!h && (!create || init_conntrack(&tuple, proto, skb)))
 			return;
 	} while (!h);
 
@@ -464,13 +470,15 @@
 }
 
 /* Return conntrack and conntrack_info a given skb */
-struct ip_conntrack *
-ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+static struct ip_conntrack *
+__ip_conntrack_get(struct sk_buff *skb,
+		   enum ip_conntrack_info *ctinfo,
+		   int create)
 {
 	if (!skb->nfct) {
 		/* It may be an icmp error... */
 		if (!icmp_error_track(skb))
-			resolve_normal_ct(skb);
+			resolve_normal_ct(skb, create);
 	}
 
 	if (skb->nfct) {
@@ -485,6 +493,12 @@
 	return NULL;
 }
 
+struct ip_conntrack *
+ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+{
+	return __ip_conntrack_get(skb, ctinfo, 0);
+}
+
 /* Netfilter hook itself. */
 unsigned int ip_conntrack_in(unsigned int hooknum,
 			     struct sk_buff **pskb,
@@ -512,13 +526,13 @@
 			return NF_STOLEN;
 	}
 
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-	if (!ct)
+	ct = __ip_conntrack_get(*pskb, &ctinfo, 1);
+	if (!ct) {
 		/* Not valid part of a connection */
 		return NF_ACCEPT;
+	}
 
 	proto = find_proto((*pskb)->nh.iph->protocol);
-	/* If this is new, this is first time timer will be set */
 	ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
 
 	if (ret == -1) {
@@ -645,24 +659,16 @@
 	MOD_DEC_USE_COUNT;
 }
 
-/* Refresh conntrack for this many jiffies: if noone calls this,
-   conntrack will vanish with current skb. */
+/* Refresh conntrack for this many jiffies. */
 void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
 {
+	IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
+
 	WRITE_LOCK(&ip_conntrack_lock);
-	/* If this hasn't had a timer before, it's still being set up */
-	if (ct->timeout.data == 0) {
-		ct->timeout.data = (unsigned long)ct;
-		ct->timeout.function = death_by_timeout;
+	/* Need del_timer for race avoidance (may already be dying). */
+	if (del_timer(&ct->timeout)) {
 		ct->timeout.expires = jiffies + extra_jiffies;
-		atomic_inc(&ct->ct_general.use);
 		add_timer(&ct->timeout);
-	} else {
-		/* Need del_timer for race avoidance (may already be dying). */
-		if (del_timer(&ct->timeout)) {
-			ct->timeout.expires = jiffies + extra_jiffies;
-			add_timer(&ct->timeout);
-		}
 	}
 	WRITE_UNLOCK(&ip_conntrack_lock);
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Fri Apr 14 09:37:53 2000
@@ -48,9 +48,10 @@
 }
 
 /* Called when a new connection for this protocol found. */
-static int new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len)
+static unsigned long
+new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len)
 {
-	return 1;
+	return GENERIC_TIMEOUT;
 }
 
 struct ip_conntrack_protocol ip_conntrack_generic_protocol
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Fri Apr 14 09:37:57 2000
@@ -86,8 +86,8 @@
 }
 
 /* Called when a new connection for this protocol found. */
-static int icmp_new(struct ip_conntrack *conntrack,
-		     struct iphdr *iph, size_t len)
+static unsigned long icmp_new(struct ip_conntrack *conntrack,
+			      struct iphdr *iph, size_t len)
 {
 	static u_int8_t valid_new[]
 		= { [ICMP_ECHO] = 1,
@@ -103,7 +103,7 @@
 		DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
 		return 0;
 	}
-	return 1;
+	return ICMP_TIMEOUT;
 }
 
 struct ip_conntrack_protocol ip_conntrack_protocol_icmp
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Fri Apr 14 09:38:00 2000
@@ -189,14 +189,13 @@
 	conntrack->proto.tcp_state = newconntrack;
 	WRITE_UNLOCK(&tcp_lock);
 
-	/* Refresh: need write lock to write to conntrack. */
 	ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]);
 	return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
-static int tcp_new(struct ip_conntrack *conntrack,
-		   struct iphdr *iph, size_t len)
+static unsigned long tcp_new(struct ip_conntrack *conntrack,
+			     struct iphdr *iph, size_t len)
 {
 	enum tcp_conntrack newconntrack;
 	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
@@ -210,11 +209,10 @@
 	if (newconntrack == TCP_CONNTRACK_MAX) {
 		DEBUGP("ip_conntrack_tcp: invalid new deleting.\n");
 		return 0;
-	} else {
-		conntrack->proto.tcp_state = newconntrack;
-		ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]);
 	}
-	return 1;
+
+	conntrack->proto.tcp_state = newconntrack;
+	return tcp_timeouts[conntrack->proto.tcp_state];
 }
 
 struct ip_conntrack_protocol ip_conntrack_protocol_tcp
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Fri Apr 14 09:38:02 2000
@@ -54,10 +54,10 @@
 }
 
 /* Called when a new connection for this protocol found. */
-static int udp_new(struct ip_conntrack *conntrack,
-		    struct iphdr *iph, size_t len)
+static unsigned long udp_new(struct ip_conntrack *conntrack,
+			     struct iphdr *iph, size_t len)
 {
-	return 1;
+	return UDP_TIMEOUT;
 }
 
 struct ip_conntrack_protocol ip_conntrack_protocol_udp
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Fri Apr 14 09:38:04 2000
@@ -169,8 +169,6 @@
 	   interface.  We degfragment them at LOCAL_OUT, however,
 	   so we have to refragment them here. */
 	if ((*pskb)->len > rt->u.dst.pmtu) {
-		DEBUGP("ip_conntrack: refragm %p (size %u) to %u (okfn %p)\n",
-		       *pskb, (*pskb)->len, rt->u.dst.pmtu, okfn);
 		/* No hook can be after us, so this should be OK. */
 		ip_fragment(*pskb, okfn);
 		return NF_STOLEN;
@@ -178,13 +176,29 @@
 	return NF_ACCEPT;
 }
 
+static unsigned int ip_conntrack_local(unsigned int hooknum,
+				       struct sk_buff **pskb,
+				       const struct net_device *in,
+				       const struct net_device *out,
+				       int (*okfn)(struct sk_buff *))
+{
+	/* root is playing with raw sockets. */
+	if ((*pskb)->len < sizeof(struct iphdr)
+	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+		if (net_ratelimit())
+			printk("ipt_hook: happy cracking.\n");
+		return NF_ACCEPT;
+	}
+	return ip_conntrack_in(hooknum, pskb, in, out, okfn);
+}
+
 /* Connection tracking may drop packets, but never alters them, so
    make it the first hook. */
 static struct nf_hook_ops ip_conntrack_in_ops
 = { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING,
 	NF_IP_PRI_CONNTRACK };
 static struct nf_hook_ops ip_conntrack_local_out_ops
-= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_LOCAL_OUT,
+= { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT,
 	NF_IP_PRI_CONNTRACK };
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ip_conntrack_out_ops
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_nat_standalone.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	Fri Apr 14 10:07:44 2000
@@ -130,6 +130,11 @@
 	   const struct net_device *out,
 	   int (*okfn)(struct sk_buff *))
 {
+	/* root is playing with raw sockets. */
+	if ((*pskb)->len < sizeof(struct iphdr)
+	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+		return NF_ACCEPT;
+
 	/* We can hit fragment here; forwarded packets get
 	   defragmented by connection tracking coming in, then
 	   fragmented (grr) by the forward code.
@@ -150,6 +155,21 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
+static unsigned int
+ip_nat_local_fn(unsigned int hooknum,
+		struct sk_buff **pskb,
+		const struct net_device *in,
+		const struct net_device *out,
+		int (*okfn)(struct sk_buff *))
+{
+	/* root is playing with raw sockets. */
+	if ((*pskb)->len < sizeof(struct iphdr)
+	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+		return NF_ACCEPT;
+
+	return ip_nat_fn(hooknum, pskb, in, out, okfn);
+}
+
 /* We must be after connection tracking and before packet filtering. */
 
 /* Before packet filtering, change destination */
@@ -160,7 +180,7 @@
 = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops
-= { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST };
+= { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST };
 
 /* Protocol registration. */
 int ip_nat_protocol_register(struct ip_nat_protocol *proto)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_queue.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_queue.c	Fri Apr 14 09:38:06 2000
@@ -509,7 +509,7 @@
 	              "Peer pid            : %d\n"
 	              "Peer died           : %d\n"
 	              "Peer copy mode      : %d\n"
-	              "Peer copy range     : %d\n"
+	              "Peer copy range     : %Zu\n"
 	              "Queue length        : %d\n"
 	              "Queue max. length   : %d\n"
 	              "Queue flushing      : %d\n"
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ip_tables.c linux/net/ipv4/netfilter/ip_tables.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ip_tables.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ip_tables.c	Fri Apr 14 09:38:10 2000
@@ -39,7 +39,7 @@
 #define IP_NF_ASSERT(x)						\
 do {								\
 	if (!(x))						\
-		printk("IPT_ASSERT: %s:%s:%u\n",		\
+		printk("IP_NF_ASSERT: %s:%s:%u\n",		\
 		       __FUNCTION__, __FILE__, __LINE__);	\
 } while(0)
 #else
@@ -683,7 +683,6 @@
 	target = find_target_lock(t->u.name, &ret, &ipt_mutex);
 	if (!target) {
 		duprintf("check_entry: `%s' not found\n", t->u.name);
-		up(&ipt_mutex);
 		return ret;
 	}
 	if (target->me)
@@ -1283,17 +1282,16 @@
 {
 	int ret;
 
+	MOD_INC_USE_COUNT;
 	ret = down_interruptible(&ipt_mutex);
 	if (ret != 0)
 		return ret;
 
-	if (list_named_insert(&ipt_target, target)) {
-		MOD_INC_USE_COUNT;
-		ret = 0;
-	} else {
+	if (!list_named_insert(&ipt_target, target)) {
 		duprintf("ipt_register_target: `%s' already in list!\n",
 			 target->name);
 		ret = -EINVAL;
+		MOD_DEC_USE_COUNT;
 	}
 	up(&ipt_mutex);
 	return ret;
@@ -1313,16 +1311,18 @@
 {
 	int ret;
 
+	MOD_INC_USE_COUNT;
 	ret = down_interruptible(&ipt_mutex);
-	if (ret != 0)
+	if (ret != 0) {
+		MOD_DEC_USE_COUNT;
 		return ret;
-
+	}
 	if (list_named_insert(&ipt_match, match)) {
-		MOD_INC_USE_COUNT;
 		ret = 0;
 	} else {
 		duprintf("ipt_register_match: `%s' already in list!\n",
 			 match->name);
+		MOD_DEC_USE_COUNT;
 		ret = -EINVAL;
 	}
 	up(&ipt_mutex);
@@ -1346,10 +1346,12 @@
 	static struct ipt_table_info bootstrap
 		= { 0, 0, { 0 }, { 0 }, { }, { } };
 
+	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ipt_table_info)
 			  + SMP_ALIGN(table->table->size) * smp_num_cpus);
 	if (!newinfo) {
 		ret = -ENOMEM;
+		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 	memcpy(newinfo->entries, table->table->entries, table->table->size);
@@ -1361,12 +1363,14 @@
 			      table->table->underflow);
 	if (ret != 0) {
 		vfree(newinfo);
+		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
 	ret = down_interruptible(&ipt_mutex);
 	if (ret != 0) {
 		vfree(newinfo);
+		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
@@ -1386,7 +1390,6 @@
 
 	table->lock = RW_LOCK_UNLOCKED;
 	list_prepend(&ipt_tables, table);
-	MOD_INC_USE_COUNT;
 
  unlock:
 	up(&ipt_mutex);
@@ -1394,6 +1397,7 @@
 
  free_unlock:
 	vfree(newinfo);
+	MOD_DEC_USE_COUNT;
 	goto unlock;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ipchains_core.c linux/net/ipv4/netfilter/ipchains_core.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ipchains_core.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipchains_core.c	Thu Apr 13 17:19:57 2000
@@ -419,18 +419,10 @@
 			printk("%d ",f->ipfw.fw_redirpt);
 	}
 
-	printk("%s PROTO=%d %d.%d.%d.%d:%hu %d.%d.%d.%d:%hu"
+	printk("%s PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
 	       " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
-	       ifname, ip->protocol,
-	       (ntohl(ip->saddr)>>24)&0xFF,
-	       (ntohl(ip->saddr)>>16)&0xFF,
-	       (ntohl(ip->saddr)>>8)&0xFF,
-	       (ntohl(ip->saddr))&0xFF,
-	       src_port,
-	       (ntohl(ip->daddr)>>24)&0xFF,
-	       (ntohl(ip->daddr)>>16)&0xFF,
-	       (ntohl(ip->daddr)>>8)&0xFF,
-	       (ntohl(ip->daddr))&0xFF,
+	       ifname, ip->protocol, NIPQUAD(ip->saddr),
+	       src_port, NIPQUAD(ip->daddr),
 	       dst_port,
 	       ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
 	       ntohs(ip->frag_off), ip->ttl);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ipfwadm_core.c linux/net/ipv4/netfilter/ipfwadm_core.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ipfwadm_core.c	Sun Mar 19 18:35:31 2000
+++ linux/net/ipv4/netfilter/ipfwadm_core.c	Mon Apr 24 13:59:57 2000
@@ -17,7 +17,7 @@
  *	license in recognition of the original copyright.
  *				-- Alan Cox.
  *
- *	$Id: ipfwadm_core.c,v 1.1 2000/03/17 14:42:00 davem Exp $
+ *	$Id: ipfwadm_core.c,v 1.2 2000/04/15 01:48:10 davem Exp $
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
@@ -143,10 +143,7 @@
 #define dprintf4(a1,a2,a3,a4)
 #endif
 
-#define print_ip(a)	 printk("%d.%d.%d.%d",(ntohl(a)>>24)&0xFF,\
-					      (ntohl(a)>>16)&0xFF,\
-					      (ntohl(a)>>8)&0xFF,\
-					      (ntohl(a))&0xFF);
+#define print_ip(a)	 printk("%u.%u.%u.%u", NIPQUAD(a));
 
 #ifdef DEBUG_IP_FIREWALL
 #define dprint_ip(a)	print_ip(a)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c
--- v2.3.99-pre5/linux/net/ipv4/netfilter/ipt_LOG.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/netfilter/ipt_LOG.c	Thu Apr 13 17:19:57 2000
@@ -38,14 +38,7 @@
 	 * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
 	/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
 	printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ",
-	       (ntohl(iph->saddr)>>24)&0xFF,
-	       (ntohl(iph->saddr)>>16)&0xFF,
-	       (ntohl(iph->saddr)>>8)&0xFF,
-	       (ntohl(iph->saddr))&0xFF,
-	       (ntohl(iph->daddr)>>24)&0xFF,
-	       (ntohl(iph->daddr)>>16)&0xFF,
-	       (ntohl(iph->daddr)>>8)&0xFF,
-	       (ntohl(iph->daddr))&0xFF);
+	       NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
 
 	/* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
 	printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
@@ -210,11 +203,7 @@
 			break;
 		case ICMP_REDIRECT:
 			/* Max length: 24 "GATEWAY=255.255.255.255 " */
-			printk("GATEWAY=%u.%u.%u.%u ",
-			       (ntohl(icmph->un.gateway)>>24)&0xFF,
-			       (ntohl(icmph->un.gateway)>>16)&0xFF,
-			       (ntohl(icmph->un.gateway)>>8)&0xFF,
-			       (ntohl(icmph->un.gateway))&0xFF);
+			printk("GATEWAY=%u.%u.%u.%u ", NIPQUAD(icmph->un.gateway));
 			/* Fall through */
 		case ICMP_DEST_UNREACH:
 		case ICMP_SOURCE_QUENCH:
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.3.99-pre5/linux/net/ipv4/proc.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/proc.c	Mon Apr 24 13:59:57 2000
@@ -7,7 +7,7 @@
  *		PROC file system.  It is mainly used for debugging and
  *		statistics.
  *
- * Version:	$Id: proc.c,v 1.41 2000/01/21 23:45:57 davem Exp $
+ * Version:	$Id: proc.c,v 1.42 2000/04/16 01:11:37 davem Exp $
  *
  * Authors:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -56,7 +56,7 @@
 	int cpu;
 
 	for (cpu=0; cpu<smp_num_cpus; cpu++)
-		res += proto->stats[cpu].inuse;
+		res += proto->stats[cpu_logical_map(cpu)].inuse;
 
 	return res;
 }
@@ -99,8 +99,10 @@
 
 	sz /= sizeof(unsigned long);
 
-	for (i=0; i<2*smp_num_cpus; i++)
-		res += begin[i*sz + nr];
+	for (i=0; i<smp_num_cpus; i++) {
+		res += begin[2*cpu_logical_map(i)*sz + nr];
+		res += begin[(2*cpu_logical_map(i)+1)*sz + nr];
+	}
 	return res;
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.3.99-pre5/linux/net/ipv4/raw.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/raw.c	Wed Apr 26 12:13:17 2000
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.48 2000/01/18 08:24:15 davem Exp $
+ * Version:	$Id: raw.c,v 1.49 2000/04/25 04:13:34 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -644,26 +644,20 @@
 }
 
 struct proto raw_prot = {
-	raw_close,			/* close */
-	udp_connect,			/* connect */
-	udp_disconnect,			/* disconnect */
-	NULL,				/* accept */
+	name:		"RAW",
+	close:		raw_close,
+	connect:	udp_connect,
+	disconnect:	udp_disconnect,
 #ifdef CONFIG_IP_MROUTE
-	ipmr_ioctl,			/* ioctl */
-#else
-	NULL,				/* ioctl */
+	ioctl:		ipmr_ioctl,
 #endif
-	raw_init,			/* init */
-	NULL,				/* destroy */
-	NULL,				/* shutdown */
-	raw_setsockopt,			/* setsockopt */
-	raw_getsockopt,			/* getsockopt */
-	raw_sendmsg,			/* sendmsg */
-	raw_recvmsg,			/* recvmsg */
-	raw_bind,			/* bind */
-	raw_rcv_skb,			/* backlog_rcv */
-	raw_v4_hash,			/* hash */
-	raw_v4_unhash,			/* unhash */
-	NULL,				/* get_port */
-	"RAW",				/* name */
+	init:		raw_init,
+	setsockopt:	raw_setsockopt,
+	getsockopt:	raw_getsockopt,
+	sendmsg:	raw_sendmsg,
+	recvmsg:	raw_recvmsg,
+	bind:		raw_bind,
+	backlog_rcv:	raw_rcv_skb,
+	hash:		raw_v4_hash,
+	unhash:		raw_v4_unhash,
 };
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.3.99-pre5/linux/net/ipv4/route.c	Mon Mar 27 08:08:33 2000
+++ linux/net/ipv4/route.c	Mon Apr 24 13:59:57 2000
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.83 2000/03/23 05:34:13 davem Exp $
+ * Version:	$Id: route.c,v 1.86 2000/04/24 07:03:14 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -616,9 +616,9 @@
 #if RT_CACHE_DEBUG >= 2
 	if (rt->u.rt_next) {
 		struct rtable * trt;
-		printk("rt_cache @%02x: %08x", hash, rt->rt_dst);
+		printk("rt_cache @%02x: %u.%u.%u.%u", hash, NIPQUAD(rt->rt_dst));
 		for (trt=rt->u.rt_next; trt; trt=trt->u.rt_next)
-			printk(" . %08x", trt->rt_dst);
+			printk(" . %u.%u.%u.%u", NIPQUAD(trt->rt_dst));
 		printk("\n");
 	}
 #endif
@@ -816,10 +816,10 @@
 reject_redirect:
 #ifdef CONFIG_IP_ROUTE_VERBOSE
 	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
-		printk(KERN_INFO "Redirect from %X/%s to %X ignored."
-		       "Path = %X -> %X, tos %02x\n",
-		       ntohl(old_gw), dev->name, ntohl(new_gw),
-		       ntohl(saddr), ntohl(daddr), tos);
+		printk(KERN_INFO "Redirect from %u.%u.%u.%u on %s about %u.%u.%u.%u ignored.\n"
+		       "  Advised path = %u.%u.%u.%u -> %u.%u.%u.%u, tos %02x\n",
+		       NIPQUAD(old_gw), dev->name, NIPQUAD(new_gw),
+		       NIPQUAD(saddr), NIPQUAD(daddr), tos);
 #endif
 	in_dev_put(in_dev);
 }
@@ -836,7 +836,8 @@
 		if ((rt->rt_flags&RTCF_REDIRECTED) || rt->u.dst.expires) {
 			unsigned hash = rt_hash_code(rt->key.dst, rt->key.src^(rt->key.oif<<5), rt->key.tos);
 #if RT_CACHE_DEBUG >= 1
-			printk(KERN_DEBUG "ip_rt_advice: redirect to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos);
+			printk(KERN_DEBUG "ip_rt_advice: redirect to %u.%u.%u.%u/%02x dropped\n",
+				NIPQUAD(rt->rt_dst), rt->key.tos);
 #endif
 			rt_del(hash, rt);
 			return NULL;
@@ -896,8 +897,10 @@
 #ifdef CONFIG_IP_ROUTE_VERBOSE
 		if (IN_DEV_LOG_MARTIANS(in_dev) &&
 		    rt->u.dst.rate_tokens == ip_rt_redirect_number && net_ratelimit())
-			printk(KERN_WARNING "host %08x/if%d ignores redirects for %08x to %08x.\n",
-			       rt->rt_src, rt->rt_iif, rt->rt_dst, rt->rt_gateway);
+			printk(KERN_WARNING "host %u.%u.%u.%u/if%d ignores redirects for "
+				"%u.%u.%u.%u to %u.%u.%u.%u.\n",
+				NIPQUAD(rt->rt_src), rt->rt_iif,
+				NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_gateway));
 #endif
 	}
 out:
@@ -1061,8 +1064,9 @@
 
 static int ip_rt_bug(struct sk_buff *skb)
 {
-	printk(KERN_DEBUG "ip_rt_bug: %08x -> %08x, %s\n", skb->nh.iph->saddr,
-	       skb->nh.iph->daddr, skb->dev ? skb->dev->name : "?");
+	printk(KERN_DEBUG "ip_rt_bug: %u.%u.%u.%u -> %u.%u.%u.%u, %s\n",
+		NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr),
+		skb->dev ? skb->dev->name : "?");
 	kfree_skb(skb);
 	return 0;
 }
@@ -1499,7 +1503,8 @@
 martian_destination:
 #ifdef CONFIG_IP_ROUTE_VERBOSE
 	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
-		printk(KERN_WARNING "martian destination %08x from %08x, dev %s\n", daddr, saddr, dev->name);
+		printk(KERN_WARNING "martian destination %u.%u.%u.%u from %u.%u.%u.%u, dev %s\n",
+			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
 #endif
 e_inval:
 	err = -EINVAL;
@@ -1513,16 +1518,20 @@
 #ifdef CONFIG_IP_ROUTE_VERBOSE
 	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) {
 		/*
-		 *	RFC1812 recommenadtion, if source is martian,
+		 *	RFC1812 recommendation, if source is martian,
 		 *	the only hint is MAC header.
 		 */
-		printk(KERN_WARNING "martian source %08x for %08x, dev %s\n", saddr, daddr, dev->name);
+		printk(KERN_WARNING "martian source %u.%u.%u.%u from %u.%u.%u.%u, on dev %s\n",
+			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
 		if (dev->hard_header_len) {
 			int i;
 			unsigned char *p = skb->mac.raw;
-			printk(KERN_WARNING "ll header:");
-			for (i=0; i<dev->hard_header_len; i++, p++)
-				printk(" %02x", *p);
+			printk(KERN_WARNING "ll header: ");
+			for (i=0; i<dev->hard_header_len; i++, p++) {
+				printk("%02x", *p);
+				if(i<(dev->hard_header_len-1))
+					printk(":");
+			}
 			printk("\n");
 		}
 	}
@@ -2218,15 +2227,20 @@
 
 		memcpy(dst, src, length);
 
-#ifdef __SMP__
-		if (smp_num_cpus > 1) {
+#ifdef CONFIG_SMP
+		if (smp_num_cpus > 1 || cpu_logical_map(0) != 0) {
 			int i;
 			int cnt = length/4;
 
-			for (i=1; i<smp_num_cpus; i++) {
+			for (i=0; i<smp_num_cpus; i++) {
+				int cpu = cpu_logical_map(i);
 				int k;
 
-				src += (256/4)*sizeof(struct ip_rt_acct);
+				if (cpu == 0)
+					continue;
+
+				src = (u32*)(((u8*)ip_rt_acct) + offset +
+					     cpu*256*sizeof(struct ip_rt_acct));
 
 				for (k=0; k<cnt; k++)
 					dst[k] += src[k];
@@ -2245,7 +2259,7 @@
 
 #ifdef CONFIG_NET_CLS_ROUTE
 	for (order=0;
-	     (PAGE_SIZE<<order) < 256*sizeof(ip_rt_acct)*smp_num_cpus; order++)
+	     (PAGE_SIZE<<order) < 256*sizeof(ip_rt_acct)*NR_CPUS; order++)
 		/* NOTHING */;
 	ip_rt_acct = (struct ip_rt_acct *)__get_free_pages(GFP_KERNEL, order);
 	if (!ip_rt_acct)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.99-pre5/linux/net/ipv4/tcp.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/tcp.c	Mon Apr 24 13:59:57 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.166 2000/03/25 01:55:11 davem Exp $
+ * Version:	$Id: tcp.c,v 1.169 2000/04/20 14:41:16 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -583,9 +583,13 @@
 			answ = 0;
 		else if (sk->urginline || !tp->urg_data ||
 			 before(tp->urg_seq,tp->copied_seq) ||
-			 !before(tp->urg_seq,tp->rcv_nxt))
+			 !before(tp->urg_seq,tp->rcv_nxt)) {
 			answ = tp->rcv_nxt - tp->copied_seq;
-		else
+
+			/* Subtract 1, if FIN is in queue. */
+			if (answ && !skb_queue_empty(&sk->receive_queue))
+				answ -= ((struct sk_buff*)sk->receive_queue.prev)->h.th->fin;
+		} else
 			answ = tp->urg_seq - tp->copied_seq;
 		release_sock(sk);
 		break;
@@ -618,7 +622,7 @@
 
 	sk->max_ack_backlog = 0;
 	sk->ack_backlog = 0;
-	tp->accept_queue = NULL;
+	tp->accept_queue = tp->accept_queue_tail = NULL;
 	tp->syn_wait_lock = RW_LOCK_UNLOCKED;
 
 	lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL);
@@ -677,7 +681,7 @@
 	write_lock_bh(&tp->syn_wait_lock);
 	tp->listen_opt =NULL;
 	write_unlock_bh(&tp->syn_wait_lock);
-	tp->accept_queue = NULL;
+	tp->accept_queue = tp->accept_queue_tail = NULL;
 
 	if (lopt->qlen) {
 		for (i=0; i<TCP_SYNQ_HSIZE; i++) {
@@ -951,10 +955,14 @@
 				tmp += copy;
 				queue_it = 0;
 			}
-			skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
 
-			/* If we didn't get any memory, we need to sleep. */
-			if (skb == NULL) {
+			if (tcp_memory_free(sk)) {
+				skb = alloc_skb(tmp, GFP_KERNEL);
+				if (skb == NULL)
+					goto do_oom;
+				skb_set_owner_w(skb, sk);
+			} else {
+				/* If we didn't get any memory, we need to sleep. */
 				set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 				set_bit(SOCK_NOSPACE, &sk->socket->flags);
 
@@ -1029,6 +1037,9 @@
 		err = -EPIPE;
 	}
 	goto out;
+do_oom:
+	err = copied ? : -ENOBUFS;
+	goto out;
 do_interrupted:
 	if(copied)
 		err = copied;
@@ -2027,7 +2038,8 @@
 	}
 
 	req = tp->accept_queue;
-	tp->accept_queue = req->dl_next;
+	if ((tp->accept_queue = req->dl_next) == NULL)
+		tp->accept_queue_tail = NULL;
 
  	newsk = req->sk;
 	tcp_acceptq_removed(sk);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.99-pre5/linux/net/ipv4/tcp_input.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/tcp_input.c	Mon Apr 24 13:59:57 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.191 2000/03/25 01:55:13 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.193 2000/04/20 14:41:16 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1618,6 +1618,7 @@
 
 	tp->fin_seq = TCP_SKB_CB(skb)->end_seq;
 	tp->ack.pending = 1;
+	tp->ack.quick = 0;
 
 	sk->shutdown |= RCV_SHUTDOWN;
 
@@ -1670,9 +1671,9 @@
 
 		/* Do not send POLL_HUP for half duplex close. */
 		if (sk->shutdown == SHUTDOWN_MASK || sk->state == TCP_CLOSE)
-			sock_wake_async(sk->socket, 1, POLL_HUP);
+			sk_wake_async(sk, 1, POLL_HUP);
 		else
-			sock_wake_async(sk->socket, 1, POLL_IN);
+			sk_wake_async(sk, 1, POLL_IN);
 	}
 }
 
@@ -2207,7 +2208,7 @@
 			kill_proc(sk->proc, SIGURG, 1);
 		else
 			kill_pg(-sk->proc, SIGURG, 1);
-		sock_wake_async(sk->socket, 3, POLL_PRI);
+		sk_wake_async(sk, 3, POLL_PRI);
 	}
 
 	/* We may be adding urgent data when the last byte read was
@@ -2783,7 +2784,7 @@
 		newtp->fin_seq = req->rcv_isn;
 		newtp->urg_data = 0;
 		newtp->listen_opt = NULL;
-		newtp->accept_queue = NULL;
+		newtp->accept_queue = newtp->accept_queue_tail = NULL;
 		/* Deinitialize syn_wait_lock to trap illegal accesses. */
 		memset(&newtp->syn_wait_lock, 0, sizeof(newtp->syn_wait_lock));
 
@@ -3162,7 +3163,7 @@
 
 		if(!sk->dead) {
 			sk->state_change(sk);
-			sock_wake_async(sk->socket, 0, POLL_OUT);
+			sk_wake_async(sk, 0, POLL_OUT);
 		}
 
 		if (tp->write_pending) {
@@ -3444,7 +3445,7 @@
 				 */
 				if (!sk->dead) {
 					sk->state_change(sk);
-					sock_wake_async(sk->socket,0,POLL_OUT);
+					sk_wake_async(sk,0,POLL_OUT);
 				}
 
 				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.99-pre5/linux/net/ipv4/tcp_ipv4.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/tcp_ipv4.c	Wed Apr 26 12:13:17 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.205 2000/03/26 09:16:08 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.207 2000/04/25 04:13:34 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -1384,7 +1384,8 @@
 		    peer->v4daddr == saddr) {
 			if (xtime.tv_sec < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
 			    (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) {
-				NETDEBUG(printk(KERN_DEBUG "TW_REC: reject openreq %u/%u %08x/%u\n", peer->tcp_ts, req->ts_recent, saddr, ntohs(skb->h.th->source)));
+				NETDEBUG(printk(KERN_DEBUG "TW_REC: reject openreq %u/%u %u.%u.%u.%u/%u\n", \
+					peer->tcp_ts, req->ts_recent, NIPQUAD(saddr), ntohs(skb->h.th->source)));
 				NET_INC_STATS_BH(PAWSPassiveRejected);
 				dst_release(dst);
 				goto drop_and_free;
@@ -1402,7 +1403,9 @@
 			 * to destinations, already remembered
 			 * to the moment of synflood.
 			 */
-			NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "TCP: drop open request from %08x/%u\n", saddr, ntohs(skb->h.th->source)));
+			NETDEBUG(if (net_ratelimit()) \
+				printk(KERN_DEBUG "TCP: drop open request from %u.%u.%u.%u/%u\n", \
+					NIPQUAD(saddr), ntohs(skb->h.th->source)));
 			TCP_INC_STATS_BH(TcpAttemptFails);
 			dst_release(dst);
 			goto drop_and_free;
@@ -2169,24 +2172,23 @@
 }
 
 struct proto tcp_prot = {
-	tcp_close,			/* close */
-	tcp_v4_connect,			/* connect */
-	tcp_disconnect,			/* disconnect */
-	tcp_accept,			/* accept */
-	tcp_ioctl,			/* ioctl */
-	tcp_v4_init_sock,		/* init */
-	tcp_v4_destroy_sock,		/* destroy */
-	tcp_shutdown,			/* shutdown */
-	tcp_setsockopt,			/* setsockopt */
-	tcp_getsockopt,			/* getsockopt */
-	tcp_sendmsg,			/* sendmsg */
-	tcp_recvmsg,			/* recvmsg */
-	NULL,				/* bind */
-	tcp_v4_do_rcv,			/* backlog_rcv */
-	tcp_v4_hash,			/* hash */
-	tcp_unhash,			/* unhash */
-	tcp_v4_get_port,		/* get_port */
-	"TCP",				/* name */
+	name:		"TCP",
+	close:		tcp_close,
+	connect:	tcp_v4_connect,
+	disconnect:	tcp_disconnect,
+	accept:		tcp_accept,
+	ioctl:		tcp_ioctl,
+	init:		tcp_v4_init_sock,
+	destroy:	tcp_v4_destroy_sock,
+	shutdown:	tcp_shutdown,
+	setsockopt:	tcp_setsockopt,
+	getsockopt:	tcp_getsockopt,
+	sendmsg:	tcp_sendmsg,
+	recvmsg:	tcp_recvmsg,
+	backlog_rcv:	tcp_v4_do_rcv,
+	hash:		tcp_v4_hash,
+	unhash:		tcp_unhash,
+	get_port:	tcp_v4_get_port,
 };
 
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.3.99-pre5/linux/net/ipv4/tcp_output.c	Tue Apr 11 15:09:26 2000
+++ linux/net/ipv4/tcp_output.c	Wed Apr 12 09:12:36 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.123 2000/03/25 01:52:05 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.124 2000/04/08 07:21:24 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1121,27 +1121,22 @@
 	timeout = jiffies + ato;
 
 	/* Use new timeout only if there wasn't a older one earlier. */
-	spin_lock_bh(&sk->timer_lock);
-	if (!tp->delack_timer.prev || !del_timer(&tp->delack_timer)) {
-		sock_hold(sk);
-		tp->delack_timer.expires = timeout;
-	} else {
+	if (timer_pending(&tp->delack_timer)) {
+		unsigned long old_timeout = tp->delack_timer.expires;
+
 		/* If delack timer was blocked or is about to expire,
 		 * send ACK now.
 		 */
-		if (tp->ack.blocked || time_before_eq(tp->delack_timer.expires, jiffies+(ato>>2))) {
-			spin_unlock_bh(&sk->timer_lock);
-
+		if (tp->ack.blocked || time_before_eq(old_timeout, jiffies+(ato>>2))) {
 			tcp_send_ack(sk);
-			__sock_put(sk);
 			return;
 		}
 
-		if (time_before(timeout, tp->delack_timer.expires))
-			tp->delack_timer.expires = timeout;
+		if (!time_before(timeout, old_timeout))
+			timeout = old_timeout;
 	}
-	add_timer(&tp->delack_timer);
-	spin_unlock_bh(&sk->timer_lock);
+	if (!mod_timer(&tp->delack_timer, timeout))
+		sock_hold(sk);
 
 #ifdef TCP_FORMAL_WINDOW
 	/* Explanation. Header prediction path does not handle
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.3.99-pre5/linux/net/ipv4/tcp_timer.c	Wed Feb 16 17:03:52 2000
+++ linux/net/ipv4/tcp_timer.c	Wed Apr 12 09:12:36 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.74 2000/02/14 20:56:30 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.75 2000/04/08 07:21:25 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -49,8 +49,6 @@
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
-	spin_lock_init(&sk->timer_lock);
-
 	init_timer(&tp->retransmit_timer);
 	tp->retransmit_timer.function=&tcp_retransmit_timer;
 	tp->retransmit_timer.data = (unsigned long) sk;
@@ -76,7 +74,6 @@
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
-	spin_lock_bh(&sk->timer_lock);
 	switch (what) {
 	case TCP_TIME_RETRANS:
 		/* When seting the transmit timer the probe timer 
@@ -84,50 +81,44 @@
 		 * The delayed ack timer can be set if we are changing the
 		 * retransmit timer when removing acked frames.
 		 */
-		if(tp->probe_timer.prev && del_timer(&tp->probe_timer))
+		if (timer_pending(&tp->probe_timer) && del_timer(&tp->probe_timer))
 			__sock_put(sk);
-		if (!tp->retransmit_timer.prev || !del_timer(&tp->retransmit_timer))
-			sock_hold(sk);
 		if (when > TCP_RTO_MAX) {
 			printk(KERN_DEBUG "reset_xmit_timer sk=%p when=0x%lx, caller=%p\n", sk, when, NET_CALLER(sk));
 			when = TCP_RTO_MAX;
 		}
-		mod_timer(&tp->retransmit_timer, jiffies+when);
+		if (!mod_timer(&tp->retransmit_timer, jiffies+when))
+			sock_hold(sk);
 		break;
 
 	case TCP_TIME_DACK:
-		if (!tp->delack_timer.prev || !del_timer(&tp->delack_timer))
+		if (!mod_timer(&tp->delack_timer, jiffies+when))
 			sock_hold(sk);
-		mod_timer(&tp->delack_timer, jiffies+when);
 		break;
 
 	case TCP_TIME_PROBE0:
-		if (!tp->probe_timer.prev || !del_timer(&tp->probe_timer))
+		if (!mod_timer(&tp->probe_timer, jiffies+when))
 			sock_hold(sk);
-		mod_timer(&tp->probe_timer, jiffies+when);
-		break;	
+		break;
 
 	default:
 		printk(KERN_DEBUG "bug: unknown timer value\n");
 	};
-	spin_unlock_bh(&sk->timer_lock);
 }
 
 void tcp_clear_xmit_timers(struct sock *sk)
 {	
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
-	spin_lock_bh(&sk->timer_lock);
-	if(tp->retransmit_timer.prev && del_timer(&tp->retransmit_timer))
+	if(timer_pending(&tp->retransmit_timer) && del_timer(&tp->retransmit_timer))
 		__sock_put(sk);
-	if(tp->delack_timer.prev && del_timer(&tp->delack_timer))
+	if(timer_pending(&tp->delack_timer) && del_timer(&tp->delack_timer))
 		__sock_put(sk);
 	tp->ack.blocked = 0;
-	if(tp->probe_timer.prev && del_timer(&tp->probe_timer))
+	if(timer_pending(&tp->probe_timer) && del_timer(&tp->probe_timer))
 		__sock_put(sk);
-	if(sk->timer.prev && del_timer(&sk->timer))
+	if(timer_pending(&sk->timer) && del_timer(&sk->timer))
 		__sock_put(sk);
-	spin_unlock_bh(&sk->timer_lock);
 }
 
 static void tcp_write_err(struct sock *sk)
@@ -138,6 +129,35 @@
 	tcp_done(sk);
 }
 
+/* Do not allow orphaned sockets to eat all our resources.
+ * This is direct violation of TCP specs, but it is required
+ * to prevent DoS attacks. It is called when a retransmission timeout
+ * or zero probe timeout occurs on orphaned socket.
+ *
+ * Criterium is still not confirmed experimentally and may change.
+ * We kill the socket, if:
+ * 1. If number of orphaned sockets exceeds an administratively configured
+ *    limit.
+ * 2. Under pessimistic assumption that all the orphans eat memory not
+ *    less than this one, total consumed memory exceeds all
+ *    the available memory.
+ */
+static int tcp_out_of_resources(struct sock *sk, int do_reset)
+{
+	int orphans = atomic_read(&tcp_orphan_count);
+
+	if (orphans >= sysctl_tcp_max_orphans ||
+	    ((orphans*atomic_read(&sk->wmem_alloc))>>PAGE_SHIFT) >= num_physpages) {
+		if (net_ratelimit())
+			printk(KERN_INFO "Out of socket memory\n");
+		if (do_reset)
+			tcp_send_active_reset(sk, GFP_ATOMIC);
+		tcp_done(sk);
+		return 1;
+	}
+	return 0;
+}
+
 /* A write timeout has occurred. Process the after effects. */
 static int tcp_write_timeout(struct sock *sk)
 {
@@ -172,9 +192,14 @@
 
 			dst_negative_advice(&sk->dst_cache);
 		}
+
 		retry_until = sysctl_tcp_retries2;
-		if (sk->dead)
+		if (sk->dead) {
+			if (tcp_out_of_resources(sk, tp->retransmits < retry_until))
+				return 1;
+
 			retry_until = sysctl_tcp_orphan_retries;
+		}
 	}
 
 	if (tp->retransmits >= retry_until) {
@@ -257,7 +282,14 @@
 	 * with RFCs, only probe timer combines both retransmission timeout
 	 * and probe timeout in one bottle.				--ANK
 	 */
-	max_probes = sk->dead ? sysctl_tcp_orphan_retries : sysctl_tcp_retries2;
+	max_probes = sysctl_tcp_retries2;
+
+	if (sk->dead) {
+		if (tcp_out_of_resources(sk, tp->probes_out <= max_probes))
+			goto out_unlock;
+
+		max_probes = sysctl_tcp_orphan_retries;
+	}
 
 	if (tp->probes_out > max_probes) {
 		tcp_write_err(sk);
@@ -574,6 +606,8 @@
 	tp->retransmits++;
 	tp->rto = min(tp->rto << 1, TCP_RTO_MAX);
 	tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+	if (tp->retransmits > sysctl_tcp_retries1)
+		__sk_dst_reset(sk);
 	TCP_CHECK_TIMER(sk);
 
 out_unlock:
@@ -676,19 +710,14 @@
 
 void tcp_delete_keepalive_timer (struct sock *sk)
 {
-	spin_lock_bh(&sk->timer_lock);
-	if (sk->timer.prev && del_timer (&sk->timer))
+	if (timer_pending(&sk->timer) && del_timer (&sk->timer))
 		__sock_put(sk);
-	spin_unlock_bh(&sk->timer_lock);
 }
 
 void tcp_reset_keepalive_timer (struct sock *sk, unsigned long len)
 {
-	spin_lock_bh(&sk->timer_lock);
-	if(!sk->timer.prev || !del_timer(&sk->timer))
+	if (!mod_timer(&sk->timer, jiffies+len))
 		sock_hold(sk);
-	mod_timer(&sk->timer, jiffies+len);
-	spin_unlock_bh(&sk->timer_lock);
 }
 
 void tcp_set_keepalive(struct sock *sk, int val)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.3.99-pre5/linux/net/ipv4/udp.c	Thu Mar  2 14:36:23 2000
+++ linux/net/ipv4/udp.c	Wed Apr 26 12:13:17 2000
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.80 2000/02/27 19:51:43 davem Exp $
+ * Version:	$Id: udp.c,v 1.81 2000/04/25 04:13:34 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1041,22 +1041,17 @@
 }
 
 struct proto udp_prot = {
-	udp_close,			/* close */
-	udp_connect,			/* connect */
-	udp_disconnect,			/* disconnect */
-	NULL,				/* accept */
-	udp_ioctl,			/* ioctl */
-	NULL,				/* init */
-	NULL,				/* destroy */
-	NULL,				/* shutdown */
-	ip_setsockopt,			/* setsockopt */
-	ip_getsockopt,			/* getsockopt */
-	udp_sendmsg,			/* sendmsg */
-	udp_recvmsg,			/* recvmsg */
-	NULL,				/* bind */
-	udp_queue_rcv_skb,		/* backlog_rcv */
-	udp_v4_hash,			/* hash */
-	udp_v4_unhash,			/* unhash */
-	udp_v4_get_port,		/* good_socknum */
- 	"UDP",				/* name */
+ 	name:		"UDP",
+	close:		udp_close,
+	connect:	udp_connect,
+	disconnect:	udp_disconnect,
+	ioctl:		udp_ioctl,
+	setsockopt:	ip_setsockopt,
+	getsockopt:	ip_getsockopt,
+	sendmsg:	udp_sendmsg,
+	recvmsg:	udp_recvmsg,
+	backlog_rcv:	udp_queue_rcv_skb,
+	hash:		udp_v4_hash,
+	unhash:		udp_v4_unhash,
+	get_port:	udp_v4_get_port,
 };
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.3.99-pre5/linux/net/ipv6/af_inet6.c	Thu Mar  2 14:36:23 2000
+++ linux/net/ipv6/af_inet6.c	Wed Apr 26 12:13:17 2000
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.55 2000/02/27 19:51:47 davem Exp $
+ *	$Id: af_inet6.c,v 1.56 2000/04/25 04:13:34 davem Exp $
  *
  * 	Fixes:
  * 	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -445,45 +445,43 @@
 }
 
 struct proto_ops inet6_stream_ops = {
-	PF_INET6,
+	family:		PF_INET6,
 
-	inet6_release,
-	inet6_bind,
-	inet_stream_connect,		/* ok		*/
-	sock_no_socketpair,		/* a do nothing	*/
-	inet_accept,			/* ok		*/
-	inet6_getname, 
-	tcp_poll,			/* ok		*/
-	inet6_ioctl,			/* must change  */
-	inet_listen,			/* ok		*/
-	inet_shutdown,			/* ok		*/
-	inet_setsockopt,		/* ok		*/
-	inet_getsockopt,		/* ok		*/
-	sock_no_fcntl,			/* ok		*/
-	inet_sendmsg,			/* ok		*/
-	inet_recvmsg,			/* ok		*/
-	sock_no_mmap
+	release:	inet6_release,
+	bind:		inet6_bind,
+	connect:	inet_stream_connect,		/* ok		*/
+	socketpair:	sock_no_socketpair,		/* a do nothing	*/
+	accept:		inet_accept,			/* ok		*/
+	getname:	inet6_getname, 
+	poll:		tcp_poll,			/* ok		*/
+	ioctl:		inet6_ioctl,			/* must change  */
+	listen:		inet_listen,			/* ok		*/
+	shutdown:	inet_shutdown,			/* ok		*/
+	setsockopt:	inet_setsockopt,		/* ok		*/
+	getsockopt:	inet_getsockopt,		/* ok		*/
+	sendmsg:	inet_sendmsg,			/* ok		*/
+	recvmsg:	inet_recvmsg,			/* ok		*/
+	mmap:		sock_no_mmap,
 };
 
 struct proto_ops inet6_dgram_ops = {
-	PF_INET6,
+	family:		PF_INET6,
 
-	inet6_release,
-	inet6_bind,
-	inet_dgram_connect,		/* ok		*/
-	sock_no_socketpair,		/* a do nothing	*/
-	sock_no_accept,			/* a do nothing	*/
-	inet6_getname, 
-	datagram_poll,			/* ok		*/
-	inet6_ioctl,			/* must change  */
-	sock_no_listen,			/* ok		*/
-	inet_shutdown,			/* ok		*/
-	inet_setsockopt,		/* ok		*/
-	inet_getsockopt,		/* ok		*/
-	sock_no_fcntl,			/* ok		*/
-	inet_sendmsg,			/* ok		*/
-	inet_recvmsg,			/* ok		*/
-	sock_no_mmap,
+	release:	inet6_release,
+	bind:		inet6_bind,
+	connect:	inet_dgram_connect,		/* ok		*/
+	socketpair:	sock_no_socketpair,		/* a do nothing	*/
+	accept:		sock_no_accept,			/* a do nothing	*/
+	getname:	inet6_getname, 
+	poll:		datagram_poll,			/* ok		*/
+	ioctl:		inet6_ioctl,			/* must change  */
+	listen:		sock_no_listen,			/* ok		*/
+	shutdown:	inet_shutdown,			/* ok		*/
+	setsockopt:	inet_setsockopt,		/* ok		*/
+	getsockopt:	inet_getsockopt,		/* ok		*/
+	sendmsg:	inet_sendmsg,			/* ok		*/
+	recvmsg:	inet_recvmsg,			/* ok		*/
+	mmap:		sock_no_mmap,
 };
 
 struct net_proto_family inet6_family_ops = {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv6/proc.c linux/net/ipv6/proc.c
--- v2.3.99-pre5/linux/net/ipv6/proc.c	Tue Jan 11 22:31:46 2000
+++ linux/net/ipv6/proc.c	Mon Apr 24 13:59:57 2000
@@ -7,7 +7,7 @@
  *		PROC file system.  This is very similar to the IPv4 version,
  *		except it reports the sockets in the INET6 address family.
  *
- * Version:	$Id: proc.c,v 1.13 2000/01/09 02:19:55 davem Exp $
+ * Version:	$Id: proc.c,v 1.14 2000/04/16 01:11:37 davem Exp $
  *
  * Authors:	David S. Miller (davem@caip.rutgers.edu)
  *
@@ -32,7 +32,7 @@
 	int cpu;
 
 	for (cpu=0; cpu<smp_num_cpus; cpu++)
-		res += proto->stats[cpu].inuse;
+		res += proto->stats[cpu_logical_map(cpu)].inuse;
 
 	return res;
 }
@@ -138,8 +138,10 @@
 	unsigned long res = 0;
 	int i;
 
-	for (i=0; i<smp_num_cpus; i++)
-		res += ptr[i*size];
+	for (i=0; i<smp_num_cpus; i++) {
+		res += ptr[2*cpu_logical_map(i)*size];
+		res += ptr[(2*cpu_logical_map(i)+1)*size];
+	}
 
 	return res;
 }
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.3.99-pre5/linux/net/ipv6/raw.c	Thu Mar  2 14:36:23 2000
+++ linux/net/ipv6/raw.c	Wed Apr 26 12:13:17 2000
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.34 2000/02/27 19:51:48 davem Exp $
+ *	$Id: raw.c,v 1.35 2000/04/25 04:13:34 davem Exp $
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -786,22 +786,18 @@
 }
 
 struct proto rawv6_prot = {
-	rawv6_close,			/* close */
-	udpv6_connect,			/* connect */
-	udp_disconnect,			/* disconnect */
-	NULL,				/* accept */
-	NULL,				/* ioctl */
-	rawv6_init_sk,			/* init */
-	inet6_destroy_sock,		/* destroy */
-	NULL,				/* shutdown */
-	rawv6_setsockopt,		/* setsockopt */
-	rawv6_getsockopt,		/* getsockopt */
-	rawv6_sendmsg,			/* sendmsg */
-	rawv6_recvmsg,			/* recvmsg */
-	rawv6_bind,			/* bind */
-	rawv6_rcv_skb,			/* backlog_rcv */
-	raw_v6_hash,			/* hash */
-	raw_v6_unhash,			/* unhash */
-	NULL,				/* get_port */
-	"RAW",				/* name */
+	name:		"RAW",
+	close:		rawv6_close,
+	connect:	udpv6_connect,
+	disconnect:	udp_disconnect,
+	init:		rawv6_init_sk,
+	destroy:	inet6_destroy_sock,
+	setsockopt:	rawv6_setsockopt,
+	getsockopt:	rawv6_getsockopt,
+	sendmsg:	rawv6_sendmsg,
+	recvmsg:	rawv6_recvmsg,
+	bind:		rawv6_bind,
+	backlog_rcv:	rawv6_rcv_skb,
+	hash:		raw_v6_hash,
+	unhash:		raw_v6_unhash,
 };
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.99-pre5/linux/net/ipv6/tcp_ipv6.c	Tue Apr 11 15:09:27 2000
+++ linux/net/ipv6/tcp_ipv6.c	Wed Apr 26 12:13:17 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.122 2000/03/25 01:52:11 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.123 2000/04/25 04:13:34 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -2080,24 +2080,23 @@
 }
 
 struct proto tcpv6_prot = {
-	tcp_close,			/* close */
-	tcp_v6_connect,			/* connect */
-	tcp_disconnect,			/* disconnect */
-	tcp_accept,			/* accept */
-	tcp_ioctl,			/* ioctl */
-	tcp_v6_init_sock,		/* init */
-	tcp_v6_destroy_sock,		/* destroy */
-	tcp_shutdown,			/* shutdown */
-	tcp_setsockopt,			/* setsockopt */
-	tcp_getsockopt,			/* getsockopt */
-	tcp_sendmsg,			/* sendmsg */
-	tcp_recvmsg,			/* recvmsg */
-	NULL,				/* bind */
-	tcp_v6_do_rcv,			/* backlog_rcv */
-	tcp_v6_hash,			/* hash */
-	tcp_unhash,			/* unhash */
-	tcp_v6_get_port,		/* get_port */
-	"TCPv6",			/* name */
+	name:		"TCPv6",
+	close:		tcp_close,
+	connect:	tcp_v6_connect,
+	disconnect:	tcp_disconnect,
+	accept:		tcp_accept,
+	ioctl:		tcp_ioctl,
+	init:		tcp_v6_init_sock,
+	destroy:	tcp_v6_destroy_sock,
+	shutdown:	tcp_shutdown,
+	setsockopt:	tcp_setsockopt,
+	getsockopt:	tcp_getsockopt,
+	sendmsg:	tcp_sendmsg,
+	recvmsg:	tcp_recvmsg,
+	backlog_rcv:	tcp_v6_do_rcv,
+	hash:		tcp_v6_hash,
+	unhash:		tcp_unhash,
+	get_port:	tcp_v6_get_port,
 };
 
 static struct inet6_protocol tcpv6_protocol =
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.3.99-pre5/linux/net/ipv6/udp.c	Thu Mar  2 14:36:23 2000
+++ linux/net/ipv6/udp.c	Wed Apr 26 12:13:17 2000
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.51 2000/02/27 19:51:51 davem Exp $
+ *	$Id: udp.c,v 1.52 2000/04/25 04:13:34 davem Exp $
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -972,24 +972,20 @@
 }
 
 struct proto udpv6_prot = {
-	udpv6_close,			/* close */
-	udpv6_connect,			/* connect */
-	udp_disconnect,			/* disconnect */
-	NULL,				/* accept */
-	udp_ioctl,			/* ioctl */
-	NULL,				/* init */
-	inet6_destroy_sock,		/* destroy */
-	NULL,				/* shutdown */
-	ipv6_setsockopt,		/* setsockopt */
-	ipv6_getsockopt,		/* getsockopt */
-	udpv6_sendmsg,			/* sendmsg */
-	udpv6_recvmsg,			/* recvmsg */
-	NULL,				/* bind */
-	udpv6_queue_rcv_skb,		/* backlog_rcv */
-	udp_v6_hash,			/* hash */
-	udp_v6_unhash,			/* unhash */
-	udp_v6_get_port,		/* get_port */
-	"UDP",				/* name */
+	name:		"UDP",
+	close:		udpv6_close,
+	connect:	udpv6_connect,
+	disconnect:	udp_disconnect,
+	ioctl:		udp_ioctl,
+	destroy:	inet6_destroy_sock,
+	setsockopt:	ipv6_setsockopt,
+	getsockopt:	ipv6_getsockopt,
+	sendmsg:	udpv6_sendmsg,
+	recvmsg:	udpv6_recvmsg,
+	backlog_rcv:	udpv6_queue_rcv_skb,
+	hash:		udp_v6_hash,
+	unhash:		udp_v6_unhash,
+	get_port:	udp_v6_get_port,
 };
 
 void __init udpv6_init(void)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.3.99-pre5/linux/net/ipx/af_ipx.c	Thu Mar  2 14:36:23 2000
+++ linux/net/ipx/af_ipx.c	Mon Apr 24 13:43:05 2000
@@ -2330,23 +2330,23 @@
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
-	PF_IPX,
-	ipx_release,
-	ipx_bind,
-	ipx_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	ipx_getname,
-	datagram_poll,
-	ipx_ioctl,
-	sock_no_listen,
-	sock_no_shutdown, /* FIXME: We have to really support shutdown. */
-	ipx_setsockopt,
-	ipx_getsockopt,
-	sock_no_fcntl,
-	ipx_sendmsg,
-	ipx_recvmsg,
-	sock_no_mmap
+	family:		PF_IPX,
+
+	release:	ipx_release,
+	bind:		ipx_bind,
+	connect:	ipx_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	ipx_getname,
+	poll:		datagram_poll,
+	ioctl:		ipx_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	sock_no_shutdown, /* FIXME: We have to really support shutdown. */
+	setsockopt:	ipx_setsockopt,
+	getsockopt:	ipx_getsockopt,
+	sendmsg:	ipx_sendmsg,
+	recvmsg:	ipx_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c
--- v2.3.99-pre5/linux/net/ipx/af_spx.c	Tue Apr 11 15:09:27 2000
+++ linux/net/ipx/af_spx.c	Mon Apr 24 13:43:05 2000
@@ -884,23 +884,23 @@
 }
 
 static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {
-        PF_IPX,
-        spx_release,
-        spx_bind,
-        spx_connect,
-        sock_no_socketpair,
-        spx_accept,
-	spx_getname,
-        spx_datagram_poll,
-	spx_ioctl,
-        spx_listen,
-        sock_no_shutdown,
-	spx_setsockopt,
-	spx_getsockopt,
-        sock_no_fcntl,
-        spx_sendmsg,
-        spx_recvmsg,
-	sock_no_mmap
+	family:		PF_IPX,
+
+	release:	spx_release,
+	bind:		spx_bind,
+	connect:	spx_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		spx_accept,
+	getname:	spx_getname,
+	poll:		spx_datagram_poll,
+	ioctl:		spx_ioctl,
+	listen:		spx_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	spx_setsockopt,
+	getsockopt:	spx_getsockopt,
+	sendmsg:	spx_sendmsg,
+	recvmsg:	spx_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.3.99-pre5/linux/net/irda/af_irda.c	Fri Jan 28 15:09:09 2000
+++ linux/net/irda/af_irda.c	Mon Apr 24 13:43:05 2000
@@ -1215,9 +1215,9 @@
 static void irda_data_wait(struct sock *sk)
 {
 	if (!skb_peek(&sk->receive_queue)) {
-		sk->socket->flags |= SO_WAITDATA;
+		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 		interruptible_sleep_on(sk->sleep);
-		sk->socket->flags &= ~SO_WAITDATA;
+		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 	}
 }
 
@@ -1241,7 +1241,7 @@
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
 
-	if (sock->flags & SO_ACCEPTCON) 
+	if (sock->flags & __SO_ACCEPTCON) 
 		return(-EINVAL);
 
 	if (flags & MSG_OOB)
@@ -2015,88 +2015,84 @@
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = {
-	PF_IRDA,
+	family:		PF_IRDA,
 	
-	irda_release,
-	irda_bind,
-	irda_connect,
-	sock_no_socketpair,
-	irda_accept,
-	irda_getname,
-	irda_poll,
-	irda_ioctl,
-	irda_listen,
-	irda_shutdown,
-	irda_setsockopt,
-	irda_getsockopt,
-	sock_no_fcntl,
-	irda_sendmsg,
-	irda_recvmsg_stream,
-	sock_no_mmap
+	release:	irda_release,
+	bind:		irda_bind,
+	connect:	irda_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		irda_accept,
+	getname:	irda_getname,
+	poll:		irda_poll,
+	ioctl:		irda_ioctl,
+	listen:		irda_listen,
+	shutdown:	irda_shutdown,
+	setsockopt:	irda_setsockopt,
+	getsockopt:	irda_getsockopt,
+	sendmsg:	irda_sendmsg,
+	recvmsg:	irda_recvmsg_stream,
+	mmap:		sock_no_mmap,
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = {
-	PF_IRDA,
+	family:		PF_IRDA,
 	
-	irda_release,
-	irda_bind,
-	irda_connect,
-	sock_no_socketpair,
-	irda_accept,
-	irda_getname,
-	datagram_poll,
-	irda_ioctl,
-	irda_listen,
-	irda_shutdown,
-	irda_setsockopt,
-	irda_getsockopt,
-	sock_no_fcntl,
-	irda_sendmsg,
-	irda_recvmsg_dgram,
-	sock_no_mmap,
+	release:	irda_release,
+	bind:		irda_bind,
+	connect:	irda_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		irda_accept,
+	getname:	irda_getname,
+	poll:		datagram_poll,
+	ioctl:		irda_ioctl,
+	listen:		irda_listen,
+	shutdown:	irda_shutdown,
+	setsockopt:	irda_setsockopt,
+	getsockopt:	irda_getsockopt,
+	sendmsg:	irda_sendmsg,
+	recvmsg:	irda_recvmsg_dgram,
+	mmap:		sock_no_mmap,
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {
-	PF_IRDA,
+	family:		PF_IRDA,
        
-	irda_release,
-	irda_bind,
-	irda_connect,
-	sock_no_socketpair,
-	irda_accept,
-	irda_getname,
-	datagram_poll,
-	irda_ioctl,
-	irda_listen,
-	irda_shutdown,
-	irda_setsockopt,
-	irda_getsockopt,
-	sock_no_fcntl,
-	irda_sendmsg_dgram,
-	irda_recvmsg_dgram,
-	sock_no_mmap,
+	release:	irda_release,
+	bind:		irda_bind,
+	connect:	irda_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		irda_accept,
+	getname:	irda_getname,
+	poll:		datagram_poll,
+	ioctl:		irda_ioctl,
+	listen:		irda_listen,
+	shutdown:	irda_shutdown,
+	setsockopt:	irda_setsockopt,
+	getsockopt:	irda_getsockopt,
+	sendmsg:	irda_sendmsg_dgram,
+	recvmsg:	irda_recvmsg_dgram,
+	mmap:		sock_no_mmap,
 };
 
 #ifdef CONFIG_IRDA_ULTRA
 static struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = {
-	PF_IRDA,
+	family:		PF_IRDA,
        
-	irda_release,
-	irda_bind,
-	sock_no_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	irda_getname,
-	datagram_poll,
-	irda_ioctl,
-	sock_no_listen,
-	irda_shutdown,
-	irda_setsockopt,
-	irda_getsockopt,
-	sock_no_fcntl,
-	irda_sendmsg_ultra,
-	irda_recvmsg_dgram,
-	sock_no_mmap,
+	release:	irda_release,
+	bind:		irda_bind,
+	connect:	sock_no_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	irda_getname,
+	poll:		datagram_poll,
+	ioctl:		irda_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	irda_shutdown,
+	setsockopt:	irda_setsockopt,
+	getsockopt:	irda_getsockopt,
+	sendmsg:	irda_sendmsg_ultra,
+	recvmsg:	irda_recvmsg_dgram,
+	mmap:		sock_no_mmap,
 };
 #endif /* CONFIG_IRDA_ULTRA */
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
--- v2.3.99-pre5/linux/net/irda/ircomm/ircomm_tty.c	Sat Feb 26 22:32:08 2000
+++ linux/net/irda/ircomm/ircomm_tty.c	Fri Apr 21 15:17:57 2000
@@ -1346,7 +1346,7 @@
 done:
         if (offset >= count+begin)
                 return 0;
-        *start = buf + (begin-offset);
+        *start = buf + (offset-begin);
         return ((len < begin+count-offset) ? len : begin+count-offset);
 }
 
diff -u --recursive --new-file v2.3.99-pre5/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.3.99-pre5/linux/net/netlink/af_netlink.c	Tue Apr 11 15:09:27 2000
+++ linux/net/netlink/af_netlink.c	Mon Apr 24 13:43:05 2000
@@ -941,24 +941,23 @@
 #endif
 
 struct proto_ops netlink_ops = {
-	PF_NETLINK,
+	family:		PF_NETLINK,
 
-	netlink_release,
-	netlink_bind,
-	netlink_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	netlink_getname,
-	datagram_poll,
-	sock_no_ioctl,
-	sock_no_listen,
-	sock_no_shutdown,
-	sock_no_setsockopt,
-	sock_no_getsockopt,
-	sock_no_fcntl,
-	netlink_sendmsg,
-	netlink_recvmsg,
-	sock_no_mmap
+	release:	netlink_release,
+	bind:		netlink_bind,
+	connect:	netlink_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	netlink_getname,
+	poll:		datagram_poll,
+	ioctl:		sock_no_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	sock_no_setsockopt,
+	getsockopt:	sock_no_getsockopt,
+	sendmsg:	netlink_sendmsg,
+	recvmsg:	netlink_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 struct net_proto_family netlink_family_ops = {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.3.99-pre5/linux/net/netrom/af_netrom.c	Tue Feb  1 01:35:44 2000
+++ linux/net/netrom/af_netrom.c	Mon Apr 24 13:43:05 2000
@@ -1240,24 +1240,23 @@
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = {
-	PF_NETROM,
+	family:		PF_NETROM,
 
-	nr_release,
-	nr_bind,
-	nr_connect,
-	sock_no_socketpair,
-	nr_accept,
-	nr_getname,
-	datagram_poll,
-	nr_ioctl,
-	nr_listen,
-	sock_no_shutdown,
-	nr_setsockopt,
-	nr_getsockopt,
-	sock_no_fcntl,
-	nr_sendmsg,
-	nr_recvmsg,
-	sock_no_mmap
+	release:	nr_release,
+	bind:		nr_bind,
+	connect:	nr_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		nr_accept,
+	getname:	nr_getname,
+	poll:		datagram_poll,
+	ioctl:		nr_ioctl,
+	listen:		nr_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	nr_setsockopt,
+	getsockopt:	nr_getsockopt,
+	sendmsg:	nr_sendmsg,
+	recvmsg:	nr_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.99-pre5/linux/net/netsyms.c	Tue Apr 11 15:09:27 2000
+++ linux/net/netsyms.c	Mon Apr 24 13:43:05 2000
@@ -134,7 +134,6 @@
 EXPORT_SYMBOL(sock_no_shutdown);
 EXPORT_SYMBOL(sock_no_getsockopt);
 EXPORT_SYMBOL(sock_no_setsockopt);
-EXPORT_SYMBOL(sock_no_fcntl);
 EXPORT_SYMBOL(sock_no_sendmsg);
 EXPORT_SYMBOL(sock_no_recvmsg);
 EXPORT_SYMBOL(sock_no_mmap);
diff -u --recursive --new-file v2.3.99-pre5/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.3.99-pre5/linux/net/packet/af_packet.c	Tue Mar 14 19:10:40 2000
+++ linux/net/packet/af_packet.c	Wed Apr 26 12:13:17 2000
@@ -5,7 +5,7 @@
  *
  *		PACKET - implements raw packet sockets.
  *
- * Version:	$Id: af_packet.c,v 1.33 2000/03/13 22:11:50 davem Exp $
+ * Version:	$Id: af_packet.c,v 1.34 2000/04/25 04:13:35 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1723,46 +1723,44 @@
 
 #ifdef CONFIG_SOCK_PACKET
 struct proto_ops packet_ops_spkt = {
-	PF_PACKET,
+	family:		PF_PACKET,
 
-	packet_release,
-	packet_bind_spkt,
-	sock_no_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	packet_getname_spkt,
-	datagram_poll,
-	packet_ioctl,
-	sock_no_listen,
-	sock_no_shutdown,
-	sock_no_setsockopt,
-	sock_no_getsockopt,
-	sock_no_fcntl,
-	packet_sendmsg_spkt,
-	packet_recvmsg,
-	sock_no_mmap
+	release:	packet_release,
+	bind:		packet_bind_spkt,
+	connect:	sock_no_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	packet_getname_spkt,
+	poll:		datagram_poll,
+	ioctl:		packet_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	sock_no_setsockopt,
+	getsockopt:	sock_no_getsockopt,
+	sendmsg:	packet_sendmsg_spkt,
+	recvmsg:	packet_recvmsg,
+	mmap:		sock_no_mmap,
 };
 #endif
 
 struct proto_ops packet_ops = {
-	PF_PACKET,
+	family:		PF_PACKET,
 
-	packet_release,
-	packet_bind,
-	sock_no_connect,
-	sock_no_socketpair,
-	sock_no_accept,
-	packet_getname, 
-	packet_poll,
-	packet_ioctl,
-	sock_no_listen,
-	sock_no_shutdown,
-	packet_setsockopt,
-	packet_getsockopt,
-	sock_no_fcntl,
-	packet_sendmsg,
-	packet_recvmsg,
-	packet_mmap,
+	release:	packet_release,
+	bind:		packet_bind,
+	connect:	sock_no_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	packet_getname, 
+	poll:		packet_poll,
+	ioctl:		packet_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	packet_setsockopt,
+	getsockopt:	packet_getsockopt,
+	sendmsg:	packet_sendmsg,
+	recvmsg:	packet_recvmsg,
+	mmap:		packet_mmap,
 };
 
 static struct net_proto_family packet_family_ops = {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.3.99-pre5/linux/net/rose/af_rose.c	Tue Feb  1 01:35:44 2000
+++ linux/net/rose/af_rose.c	Mon Apr 24 13:43:05 2000
@@ -1410,24 +1410,23 @@
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = {
-	PF_ROSE,
+	family:		PF_ROSE,
 
-	rose_release,
-	rose_bind,
-	rose_connect,
-	sock_no_socketpair,
-	rose_accept,
-	rose_getname,
-	datagram_poll,
-	rose_ioctl,
-	rose_listen,
-	sock_no_shutdown,
-	rose_setsockopt,
-	rose_getsockopt,
-	sock_no_fcntl,
-	rose_sendmsg,
-	rose_recvmsg,
-	sock_no_mmap
+	release:	rose_release,
+	bind:		rose_bind,
+	connect:	rose_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		rose_accept,
+	getname:	rose_getname,
+	poll:		datagram_poll,
+	ioctl:		rose_ioctl,
+	listen:		rose_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	rose_setsockopt,
+	getsockopt:	rose_getsockopt,
+	sendmsg:	rose_sendmsg,
+	recvmsg:	rose_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/net/sched/sch_gred.c linux/net/sched/sch_gred.c
--- v2.3.99-pre5/linux/net/sched/sch_gred.c	Tue Feb  1 01:35:44 2000
+++ linux/net/sched/sch_gred.c	Fri Apr 14 09:38:10 2000
@@ -512,7 +512,7 @@
 	opt=kmalloc(sizeof(struct tc_gred_qopt)*MAX_DPs, GFP_KERNEL);
 
 	if (opt  == NULL) {
-		DPRINTK("gred_dump:failed to malloc for %d\n",
+		DPRINTK("gred_dump:failed to malloc for %Zd\n",
 		    sizeof(struct tc_gred_qopt)*MAX_DPs);
 		goto rtattr_failure;
 	}
diff -u --recursive --new-file v2.3.99-pre5/linux/net/socket.c linux/net/socket.c
--- v2.3.99-pre5/linux/net/socket.c	Tue Apr 11 15:09:27 2000
+++ linux/net/socket.c	Mon Apr 24 13:59:57 2000
@@ -130,7 +130,7 @@
 
 static struct net_proto_family *net_families[NPROTO];
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 static atomic_t net_family_lockct = ATOMIC_INIT(0);
 static spinlock_t net_family_lock = SPIN_LOCK_UNLOCKED;
 
@@ -561,21 +561,16 @@
 }
 
 
+/* No kernel lock held - perfect */
 static unsigned int sock_poll(struct file *file, poll_table * wait)
 {
 	struct socket *sock;
-	int err;
-
-	unlock_kernel();
-	sock = socki_lookup(file->f_dentry->d_inode);
 
 	/*
 	 *	We can't return errors to poll, so it's either yes or no. 
 	 */
-
-	err = sock->ops->poll(file, sock, wait);
-	lock_kernel();
-	return err;
+	sock = socki_lookup(file->f_dentry->d_inode);
+	return sock->ops->poll(file, sock, wait);
 }
 
 static int sock_mmap(struct file * file, struct vm_area_struct * vma)
@@ -1397,7 +1392,7 @@
 
 	sock = socki_lookup (filp->f_dentry->d_inode);
 	if (sock && sock->ops)
-		return sock->ops->fcntl(sock, cmd, arg);
+		return sock_no_fcntl(sock, cmd, arg);
 	return(-EINVAL);
 }
 
@@ -1618,7 +1613,7 @@
 	int counter = 0;
 
 	for (cpu=0; cpu<smp_num_cpus; cpu++)
-		counter += sockets_in_use[cpu].counter;
+		counter += sockets_in_use[cpu_logical_map(cpu)].counter;
 
 	/* It can be negative, by the way. 8) */
 	if (counter < 0)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/sunrpc/Makefile linux/net/sunrpc/Makefile
--- v2.3.99-pre5/linux/net/sunrpc/Makefile	Mon Apr  7 11:35:33 1997
+++ linux/net/sunrpc/Makefile	Fri Apr 21 16:08:52 2000
@@ -11,11 +11,15 @@
 O_OBJS   := clnt.o xprt.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
 	    svc.o svcsock.o svcauth.o \
-	    pmap_clnt.o xdr.o sysctl.o
+	    pmap_clnt.o xdr.o
 OX_OBJS  := sunrpc_syms.o
 
 ifeq ($(CONFIG_PROC_FS),y)
   O_OBJS     += stats.o
+endif
+
+ifeq ($(CONFIG_SYSCTL),y)
+  O_OBJS     += sysctl.o
 endif
 
 M_OBJS   := $(O_TARGET)
diff -u --recursive --new-file v2.3.99-pre5/linux/net/sunrpc/pmap_clnt.c linux/net/sunrpc/pmap_clnt.c
--- v2.3.99-pre5/linux/net/sunrpc/pmap_clnt.c	Mon Mar 27 08:08:34 2000
+++ linux/net/sunrpc/pmap_clnt.c	Thu Apr 13 17:19:57 2000
@@ -91,8 +91,8 @@
 	char		hostname[32];
 	int		status;
 
-	dprintk("RPC:      rpc_getport_external(%s, %d, %d, %d)\n",
-			in_ntoa(sin->sin_addr.s_addr), prog, vers, prot);
+	dprintk("RPC:      rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)\n",
+			NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 
 	strcpy(hostname, in_ntoa(sin->sin_addr.s_addr));
 	if (!(pmap_clnt = pmap_create(hostname, sin, prot)))
diff -u --recursive --new-file v2.3.99-pre5/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.3.99-pre5/linux/net/sunrpc/sched.c	Tue Apr 11 15:09:27 2000
+++ linux/net/sunrpc/sched.c	Fri Apr 21 16:08:52 2000
@@ -1015,7 +1015,7 @@
 
 	current->session = 1;
 	current->pgrp = 1;
-	sprintf(current->comm, "rpciod");
+	strcpy(current->comm, "rpciod");
 
 	dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
 	while (rpciod_users) {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/sunrpc/sunrpc_syms.c linux/net/sunrpc/sunrpc_syms.c
--- v2.3.99-pre5/linux/net/sunrpc/sunrpc_syms.c	Tue Apr 11 15:09:27 2000
+++ linux/net/sunrpc/sunrpc_syms.c	Fri Apr 21 16:08:52 2000
@@ -95,6 +95,7 @@
 EXPORT_SYMBOL(xdr_encode_netobj);
 EXPORT_SYMBOL(xdr_zero);
 EXPORT_SYMBOL(xdr_one);
+EXPORT_SYMBOL(xdr_two);
 EXPORT_SYMBOL(xdr_shift_iovec);
 EXPORT_SYMBOL(xdr_zero_iovec);
 
@@ -104,7 +105,9 @@
 EXPORT_SYMBOL(rpc_system_err);
 
 /* Debugging symbols */
+#ifdef RPC_DEBUG
 EXPORT_SYMBOL(rpc_debug);
 EXPORT_SYMBOL(nfs_debug);
 EXPORT_SYMBOL(nfsd_debug);
 EXPORT_SYMBOL(nlm_debug);
+#endif
diff -u --recursive --new-file v2.3.99-pre5/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.3.99-pre5/linux/net/sunrpc/svcsock.c	Tue Apr 11 15:09:27 2000
+++ linux/net/sunrpc/svcsock.c	Thu Apr 13 17:19:57 2000
@@ -544,14 +544,14 @@
 	if (ntohs(sin.sin_port) >= 1024) {
 		if (net_ratelimit())
 			printk(KERN_WARNING
-				   "%s: connect from unprivileged port: %s:%d",
+				   "%s: connect from unprivileged port: %u.%u.%u.%u:%d",
 				   serv->sv_name, 
-				   in_ntoa(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+				   NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
 		goto failed;
 	}
 
-	dprintk("%s: connect from %s:%04x\n", serv->sv_name,
-			in_ntoa(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+	dprintk("%s: connect from %u.%u.%u.%u:%04x\n", serv->sv_name,
+			NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
 
 	if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0)))
 		goto failed;
@@ -915,9 +915,9 @@
 	int		error;
 	int		type;
 
-	dprintk("svc: svc_create_socket(%s, %d, %08x:%d)\n",
+	dprintk("svc: svc_create_socket(%s, %d, %u.%u.%u.%u:%d)\n",
 				serv->sv_program->pg_name, protocol,
-				ntohl(sin->sin_addr.s_addr),
+				NIPQUAD(sin->sin_addr.s_addr),
 				ntohs(sin->sin_port));
 
 	if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/sunrpc/sysctl.c linux/net/sunrpc/sysctl.c
--- v2.3.99-pre5/linux/net/sunrpc/sysctl.c	Thu Feb 10 17:11:25 2000
+++ linux/net/sunrpc/sysctl.c	Fri Apr 21 16:08:52 2000
@@ -57,7 +57,7 @@
 	}
 }
 
-int
+static int
 proc_dodebug(ctl_table *table, int write, struct file *file,
 				void *buffer, size_t *lenp)
 {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.99-pre5/linux/net/unix/af_unix.c	Tue Apr 11 15:09:27 2000
+++ linux/net/unix/af_unix.c	Wed Apr 26 12:13:17 2000
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.91 2000/03/25 01:55:34 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.94 2000/04/25 04:13:35 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -1103,6 +1103,9 @@
 	    (err = unix_autobind(sock)) != 0)
 		goto out;
 
+	err = -EMSGSIZE;
+	if ((unsigned)len > sk->sndbuf - 32)
+		goto out;
 
 	skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err);
 	if (skb==NULL)
@@ -1719,45 +1722,43 @@
 #endif
 
 struct proto_ops unix_stream_ops = {
-	PF_UNIX,
+	family:		PF_UNIX,
 	
-	unix_release,
-	unix_bind,
-	unix_stream_connect,
-	unix_socketpair,
-	unix_accept,
-	unix_getname,
-	unix_poll,
-	unix_ioctl,
-	unix_listen,
-	unix_shutdown,
-	sock_no_setsockopt,
-	sock_no_getsockopt,
-	sock_no_fcntl,
-	unix_stream_sendmsg,
-	unix_stream_recvmsg,
-	sock_no_mmap
+	release:	unix_release,
+	bind:		unix_bind,
+	connect:	unix_stream_connect,
+	socketpair:	unix_socketpair,
+	accept:		unix_accept,
+	getname:	unix_getname,
+	poll:		unix_poll,
+	ioctl:		unix_ioctl,
+	listen:		unix_listen,
+	shutdown:	unix_shutdown,
+	setsockopt:	sock_no_setsockopt,
+	getsockopt:	sock_no_getsockopt,
+	sendmsg:	unix_stream_sendmsg,
+	recvmsg:	unix_stream_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 struct proto_ops unix_dgram_ops = {
-	PF_UNIX,
+	family:		PF_UNIX,
 	
-	unix_release,
-	unix_bind,
-	unix_dgram_connect,
-	unix_socketpair,
-	sock_no_accept,
-	unix_getname,
-	datagram_poll,
-	unix_ioctl,
-	sock_no_listen,
-	unix_shutdown,
-	sock_no_setsockopt,
-	sock_no_getsockopt,
-	sock_no_fcntl,
-	unix_dgram_sendmsg,
-	unix_dgram_recvmsg,
-	sock_no_mmap
+	release:	unix_release,
+	bind:		unix_bind,
+	connect:	unix_dgram_connect,
+	socketpair:	unix_socketpair,
+	accept:		sock_no_accept,
+	getname:	unix_getname,
+	poll:		datagram_poll,
+	ioctl:		unix_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	unix_shutdown,
+	setsockopt:	sock_no_setsockopt,
+	getsockopt:	sock_no_getsockopt,
+	sendmsg:	unix_dgram_sendmsg,
+	recvmsg:	unix_dgram_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 struct net_proto_family unix_family_ops = {
diff -u --recursive --new-file v2.3.99-pre5/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.3.99-pre5/linux/net/x25/af_x25.c	Tue Mar 14 19:10:40 2000
+++ linux/net/x25/af_x25.c	Mon Apr 24 13:43:06 2000
@@ -17,6 +17,9 @@
  *	X.25 002	Jonathan Naylor	Centralised disconnect handling.
  *					New timer architecture.
  *	2000-11-03	Henner Eisen	MSG_EOR handling more POSIX compliant.
+ *	2000-22-03	Daniela Squassoni Allowed disabling/enabling of 
+ *					  facilities negotiation and increased 
+ *					  the throughput upper limit.
  */
 
 #include <linux/config.h>
@@ -811,6 +814,7 @@
 	make->protinfo.x25->source_addr   = source_addr;
 	make->protinfo.x25->neighbour     = neigh;
 	make->protinfo.x25->facilities    = facilities;
+	make->protinfo.x25->vc_facil_mask = sk->protinfo.x25->vc_facil_mask;
 
 	x25_write_internal(make, X25_CALL_ACCEPTED);
 
@@ -1133,7 +1137,7 @@
 				return -EINVAL;
 			if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
 				return -EINVAL;
-			if (facilities.throughput < 0x03 || facilities.throughput > 0x2C)
+			if (facilities.throughput < 0x03 || facilities.throughput > 0xDD)
 				return -EINVAL;
 			if (facilities.reverse != 0 && facilities.reverse != 1)
 				return -EINVAL;
@@ -1239,24 +1243,23 @@
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
-	AF_X25,
+	family:		AF_X25,
 
-	x25_release,
-	x25_bind,
-	x25_connect,
-	sock_no_socketpair,
-	x25_accept,
-	x25_getname,
-	datagram_poll,
-	x25_ioctl,
-	x25_listen,
-	sock_no_shutdown,
-	x25_setsockopt,
-	x25_getsockopt,
-	sock_no_fcntl,
-	x25_sendmsg,
-	x25_recvmsg,
-	sock_no_mmap
+	release:	x25_release,
+	bind:		x25_bind,
+	connect:	x25_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		x25_accept,
+	getname:	x25_getname,
+	poll:		datagram_poll,
+	ioctl:		x25_ioctl,
+	listen:		x25_listen,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	x25_setsockopt,
+	getsockopt:	x25_getsockopt,
+	sendmsg:	x25_sendmsg,
+	recvmsg:	x25_recvmsg,
+	mmap:		sock_no_mmap,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.3.99-pre5/linux/net/x25/x25_facilities.c linux/net/x25/x25_facilities.c
--- v2.3.99-pre5/linux/net/x25/x25_facilities.c	Sun Jul 26 23:35:58 1998
+++ linux/net/x25/x25_facilities.c	Fri Apr 14 09:38:10 2000
@@ -14,6 +14,8 @@
  *
  *	History
  *	X.25 001	Split from x25_subr.c
+ *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities 
+ *					  negotiation.
  */
 
 #include <linux/config.h>
@@ -43,12 +45,13 @@
  *	Parse a set of facilities into the facilities structure. Unrecognised
  *	facilities are written to the debug log file.
  */
-int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities)
+int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, unsigned long *vc_fac_mask)
 {
 	unsigned int len;
 	unsigned char *p = skb->data;
 
 	len = *p++;
+	*vc_fac_mask = 0;
 
 	while (len > 0) {
 		switch (*p & X25_FAC_CLASS_MASK) {
@@ -56,9 +59,11 @@
 				switch (*p) {
 					case X25_FAC_REVERSE:
 						facilities->reverse = (p[1] & 0x01);
+						*vc_fac_mask |= X25_MASK_REVERSE;
 						break;
 					case X25_FAC_THROUGHPUT:
 						facilities->throughput = p[1];
+						*vc_fac_mask |= X25_MASK_THROUGHPUT;
 						break;
 					default:
 						printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]);
@@ -73,10 +78,12 @@
 					case X25_FAC_PACKET_SIZE:
 						facilities->pacsize_in  = p[1];
 						facilities->pacsize_out = p[2];
+						*vc_fac_mask |= X25_MASK_PACKET_SIZE;
 						break;
 					case X25_FAC_WINDOW_SIZE:
 						facilities->winsize_in  = p[1];
 						facilities->winsize_out = p[2];
+						*vc_fac_mask |= X25_MASK_WINDOW_SIZE;
 						break;
 					default:
 						printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]);
@@ -106,28 +113,34 @@
 /*
  *	Create a set of facilities.
  */
-int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities)
+int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities, unsigned long facil_mask)
 {
 	unsigned char *p = buffer + 1;
 	int len;
 
-	if (facilities->reverse != 0) {
+	if (facil_mask == 0) {
+		buffer [0] = 0; /* length of the facilities field in call_req or call_accept packets */
+		len = 1; /* 1 byte for the length field */
+		return len;
+	}
+
+	if ((facilities->reverse != 0) && (facil_mask & X25_MASK_REVERSE)) {
 		*p++ = X25_FAC_REVERSE;
 		*p++ = (facilities->reverse) ? 0x01 : 0x00;
 	}
 
-	if (facilities->throughput != 0) {
+	if ((facilities->throughput != 0) && (facil_mask & X25_MASK_THROUGHPUT)) {
 		*p++ = X25_FAC_THROUGHPUT;
 		*p++ = facilities->throughput;
 	}
 
-	if (facilities->pacsize_in != 0 || facilities->pacsize_out != 0) {
+	if ((facilities->pacsize_in != 0 || facilities->pacsize_out != 0) && (facil_mask & X25_MASK_PACKET_SIZE)) {
 		*p++ = X25_FAC_PACKET_SIZE;
 		*p++ = (facilities->pacsize_in  == 0) ? facilities->pacsize_out : facilities->pacsize_in;
 		*p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in  : facilities->pacsize_out;
 	}
 
-	if (facilities->winsize_in != 0 || facilities->winsize_out != 0) {
+	if ((facilities->winsize_in != 0 || facilities->winsize_out != 0) && (facil_mask & X25_MASK_WINDOW_SIZE)) {
 		*p++ = X25_FAC_WINDOW_SIZE;
 		*p++ = (facilities->winsize_in  == 0) ? facilities->winsize_out : facilities->winsize_in;
 		*p++ = (facilities->winsize_out == 0) ? facilities->winsize_in  : facilities->winsize_out;
@@ -156,7 +169,7 @@
 
 	*new = *ours;
 
-	len = x25_parse_facilities(skb, &theirs);
+	len = x25_parse_facilities(skb, &theirs, &sk->protinfo.x25->vc_facil_mask);
 
 	/*
 	 *	They want reverse charging, we won't accept it.
diff -u --recursive --new-file v2.3.99-pre5/linux/net/x25/x25_in.c linux/net/x25/x25_in.c
--- v2.3.99-pre5/linux/net/x25/x25_in.c	Fri Oct 15 15:25:14 1999
+++ linux/net/x25/x25_in.c	Fri Apr 14 09:38:10 2000
@@ -13,9 +13,11 @@
  *		2 of the License, or (at your option) any later version.
  *
  *	History
- *	X.25 001	Jonathan Naylor	Started coding.
- *	X.25 002	Jonathan Naylor	Centralised disconnection code.
- *					New timer architecture.
+ *	X.25 001	Jonathan Naylor	  Started coding.
+ *	X.25 002	Jonathan Naylor	  Centralised disconnection code.
+ *					  New timer architecture.
+ *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities 
+ *					  negotiation.
  */
 
 #include <linux/config.h>
@@ -111,7 +113,7 @@
 			 */
 			skb_pull(skb, X25_STD_MIN_LEN);
 			skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
-			skb_pull(skb, x25_parse_facilities(skb, &sk->protinfo.x25->facilities));
+			skb_pull(skb, x25_parse_facilities(skb, &sk->protinfo.x25->facilities, &sk->protinfo.x25->vc_facil_mask));
 			/*
 			 *	Copy any Call User Data.
 			 */
diff -u --recursive --new-file v2.3.99-pre5/linux/net/x25/x25_link.c linux/net/x25/x25_link.c
--- v2.3.99-pre5/linux/net/x25/x25_link.c	Tue Mar 14 19:10:40 2000
+++ linux/net/x25/x25_link.c	Fri Apr 14 09:38:10 2000
@@ -13,8 +13,10 @@
  *		2 of the License, or (at your option) any later version.
  *
  *	History
- *	X.25 001	Jonathan Naylor	Started coding.
- *	X.25 002	Jonathan Naylor	New timer architecture.
+ *	X.25 001	Jonathan Naylor	  Started coding.
+ *	X.25 002	Jonathan Naylor	  New timer architecture.
+ *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities 
+ *					  negotiation.
  */
 
 #include <linux/config.h>
@@ -293,6 +295,7 @@
 	x25_neigh->dev      = dev;
 	x25_neigh->state    = X25_LINK_STATE_0;
 	x25_neigh->extended = 0;
+	x25_neigh->global_facil_mask = (X25_MASK_REVERSE | X25_MASK_THROUGHPUT | X25_MASK_PACKET_SIZE | X25_MASK_WINDOW_SIZE); /* enables negotiation */
 	x25_neigh->t20      = sysctl_x25_restart_request_timeout;
 
 	save_flags(flags); cli();
@@ -377,6 +380,8 @@
 	switch (cmd) {
 
 		case SIOCX25GSUBSCRIP:
+			if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
+				return -EFAULT;
 			if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
 				return -EINVAL;
 			if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
@@ -385,6 +390,7 @@
 			}
 			dev_put(dev);
 			x25_subscr.extended = x25_neigh->extended;
+			x25_subscr.global_facil_mask = x25_neigh->global_facil_mask;
 			if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
 				return -EFAULT;
 			break;
@@ -402,6 +408,7 @@
 			if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
 				return -EINVAL;
 			x25_neigh->extended = x25_subscr.extended;
+			x25_neigh->global_facil_mask = x25_subscr.global_facil_mask;
 			break;
 
 		default:
diff -u --recursive --new-file v2.3.99-pre5/linux/net/x25/x25_subr.c linux/net/x25/x25_subr.c
--- v2.3.99-pre5/linux/net/x25/x25_subr.c	Tue Feb 10 13:07:49 1998
+++ linux/net/x25/x25_subr.c	Fri Apr 14 09:38:10 2000
@@ -13,8 +13,10 @@
  *		2 of the License, or (at your option) any later version.
  *
  *	History
- *	X.25 001	Jonathan Naylor	Started coding.
- *	X.25 002	Jonathan Naylor	Centralised disconnection processing.
+ *	X.25 001	Jonathan Naylor	  Started coding.
+ *	X.25 002	Jonathan Naylor	  Centralised disconnection processing.
+ *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities 
+ *					  negotiation.
  */
 
 #include <linux/config.h>
@@ -206,7 +208,7 @@
 			len     = x25_addr_aton(addresses, &sk->protinfo.x25->dest_addr, &sk->protinfo.x25->source_addr);
 			dptr    = skb_put(skb, len);
 			memcpy(dptr, addresses, len);
-			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities);
+			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities, sk->protinfo.x25->neighbour->global_facil_mask);
 			dptr    = skb_put(skb, len);
 			memcpy(dptr, facilities, len);
 			dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
@@ -218,7 +220,7 @@
 			dptr    = skb_put(skb, 2);
 			*dptr++ = X25_CALL_ACCEPTED;
 			*dptr++ = 0x00;		/* Address lengths */
-			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities);
+			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities, sk->protinfo.x25->vc_facil_mask);
 			dptr    = skb_put(skb, len);
 			memcpy(dptr, facilities, len);
 			dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
diff -u --recursive --new-file v2.3.99-pre5/linux/scripts/Configure linux/scripts/Configure
--- v2.3.99-pre5/linux/scripts/Configure	Sun Feb 20 21:12:40 2000
+++ linux/scripts/Configure	Tue Apr 25 17:44:34 2000
@@ -321,9 +321,6 @@
 	      define_bool "$var" "n"
 	      return
 	      ;;
-	    m)
-	      eval "$var=y"
-	      ;;
 	  esac
 	  shift
 	done
diff -u --recursive --new-file v2.3.99-pre5/linux/scripts/docproc.c linux/scripts/docproc.c
--- v2.3.99-pre5/linux/scripts/docproc.c	Tue Apr 11 15:09:27 2000
+++ linux/scripts/docproc.c	Wed Apr 12 09:47:30 2000
@@ -13,6 +13,8 @@
 {
 	char buf[1024];
 	char *vec[8192];
+	char *fvec[200];
+	char **svec;
 	char type[64];
 	int i;
 	int vp=2;
@@ -46,32 +48,55 @@
 	 
 	while(fgets(buf, 1024, stdin))
 	{
-		if(*buf!='!')
+		if(*buf!='!') {
 			printf("%s", buf);
-		else
-		{
-			fflush(stdout);
-			if(buf[1]=='E')
-				strcpy(type, "-function");
-			else if(buf[1]=='I')
-				strcpy(type, "-nofunction");	
-			else
-			{
-				fprintf(stderr, "Unknown ! escape.\n");
-				exit(1);
-			}
-			switch(pid=fork())
-			{
-				case -1:
-					perror("fork");
-					exit(1);
-				case  0:
-					execvp("scripts/kernel-doc", vec);
-					perror("exec scripts/kernel-doc");
-					exit(1);
-				default:
-					waitpid(pid, NULL,0);
+			continue;
+		}
+
+		fflush(stdout);
+		svec = vec;
+		if(buf[1]=='E')
+			strcpy(type, "-function");
+		else if(buf[1]=='I')
+			strcpy(type, "-nofunction");	
+		else if(buf[1]=='F') {
+			int snarf = 0;
+			fvec[0] = "kernel-doc";
+			fvec[1] = "-docbook";
+			strcpy (type, "-function");
+			vp = 2;
+			for (i = 2; buf[i]; i++) {
+				if (buf[i] == ' ' || buf[i] == '\n') {
+					buf[i] = '\0';
+					snarf = 1;
+					continue;
+				}
+
+				if (snarf) {
+					snarf = 0;
+					fvec[vp++] = type;
+					fvec[vp++] = &buf[i];
+				}
 			}
+			fvec[vp++] = &buf[2];
+			fvec[vp] = NULL;
+			svec = fvec;
+		} else
+		{
+			fprintf(stderr, "Unknown ! escape.\n");
+			exit(1);
+		}
+		switch(pid=fork())
+		{
+		case -1:
+			perror("fork");
+			exit(1);
+		case  0:
+			execvp("scripts/kernel-doc", svec);
+			perror("exec scripts/kernel-doc");
+			exit(1);
+		default:
+			waitpid(pid, NULL,0);
 		}
 	}
 	exit(0);
diff -u --recursive --new-file v2.3.99-pre5/linux/scripts/kernel-doc linux/scripts/kernel-doc
--- v2.3.99-pre5/linux/scripts/kernel-doc	Tue Apr 11 15:09:27 2000
+++ linux/scripts/kernel-doc	Wed Apr 12 09:47:30 2000
@@ -1,9 +1,10 @@
 #!/usr/bin/perl
 
 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
+## Copyright (C) 2000  Tim Waugh <twaugh@redhat.com>             ##
 ##                                                               ##
-## This software falls under the GNU Public License. Please read ##
-##              the COPYING file for more information            ##
+## This software falls under the GNU General Public License.     ##
+## Please read the COPYING file for more information             ##
 
 #
 # This will read a 'c' file and scan for embedded comments in the
@@ -76,15 +77,15 @@
 #
 # 'funcname()' - function
 # '$ENVVAR' - environmental variable
-# '&struct_name' - name of a structure
+# '&struct_name' - name of a structure (up to two words including 'struct')
 # '@parameter' - name of a parameter
 # '%CONST' - name of a constant.
 
 # match expressions used to find embedded type information
-$type_constant = "\\\%(\\w+)";
-$type_func = "(\\w+\\(\\))";
+$type_constant = "\\\%([-_\\w]+)";
+$type_func = "(\\w+)\\(\\)";
 $type_param = "\\\@(\\w+)";
-$type_struct = "\\\&(\\w+)";
+$type_struct = "\\\&((struct\\s*)?\\w+)";
 $type_env = "(\\\$\\w+)";
 
 
@@ -99,7 +100,8 @@
 $blankline_html = "<p>";
 
 # sgml, docbook format
-%highlights_sgml = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
+%highlights_sgml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
+		     $type_constant, "<constant>\$1</constant>",
 		     $type_func, "<function>\$1</function>",
 		     $type_struct, "<structname>\$1</structname>",
 		     $type_env, "<envar>\$1</envar>",
@@ -115,10 +117,10 @@
 $blankline_gnome = "</para><para>\n";
 
 # these are pretty rough
-%highlights_man = ( $type_constant, "\\n.I \\\"\$1\\\"\\n",
-		    $type_func, "\\n.B \\\"\$1\\\"\\n",
-		    $type_struct, "\\n.I \\\"\$1\\\"\\n",
-		    $type_param."([\.\, ]*)\n?", "\\n.I \\\"\$1\$2\\\"\\n" );
+%highlights_man = ( $type_constant, "\$1",
+		    $type_func, "\\\\fB\$1\\\\fP",
+		    $type_struct, "\\\\fI\$1\\\\fP",
+		    $type_param, "\\\\fI\$1\\\\fP" );
 $blankline_man = "";
 
 # text-mode
@@ -258,10 +260,16 @@
     print "(";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
-	print "<i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parameter."</b>\n";
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print "<i>$1</i><b>$parameter</b>) <i>($2)</i>";
+	} else {
+	    print "<i>".$type."</i> <b>".$parameter."</b>";
+	}
 	if ($count != $#{$args{'parameterlist'}}) {
 	    $count++;
-	    print ", ";
+	    print ",\n";
 	}
     }
     print ")\n";
@@ -269,16 +277,16 @@
     print "<h3>Arguments</h3>\n";
     print "<dl>\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
-	print "<dt><i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parameter."</b>\n";
+	print "<dt><b>".$parameter."</b>\n";
 	print "<dd>";
 	output_highlight($args{'parameters'}{$parameter});
     }
     print "</dl>\n";
     foreach $section (@{$args{'sectionlist'}}) {
 	print "<h3>$section</h3>\n";
-	print "<ul>\n";
+	print "<blockquote>\n";
 	output_highlight($args{'sections'}{$section});
-	print "</ul>\n";
+	print "</blockquote>\n";
     }
     print "<hr>\n";
 }
@@ -339,8 +347,15 @@
     $count = 0;
     if ($#{$args{'parameterlist'}} >= 0) {
 	foreach $parameter (@{$args{'parameterlist'}}) {
-	    print "   <paramdef>".$args{'parametertypes'}{$parameter};
-	    print " <parameter>$parameter</parameter></paramdef>\n";
+	    $type = $args{'parametertypes'}{$parameter};
+	    if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+		# pointer-to-function
+		print "   <paramdef>$1<parameter>$parameter</parameter>)\n";
+		print "     <funcparams>$2</funcparams></paramdef>\n";
+	    } else {
+		print "   <paramdef>".$type;
+		print " <parameter>$parameter</parameter></paramdef>\n";
+	    }
 	}
     } else {
 	print "  <void>\n";
@@ -438,8 +453,15 @@
     $count = 0;
     if ($#{$args{'parameterlist'}} >= 0) {
 	foreach $parameter (@{$args{'parameterlist'}}) {
-	    print "   <paramdef>".$args{'parametertypes'}{$parameter};
-	    print " <parameter>$parameter</parameter></paramdef>\n";
+	    $type = $args{'parametertypes'}{$parameter};
+	    if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+		# pointer-to-function
+		print "   <paramdef>$1 <parameter>$parameter</parameter>)\n";
+		print "     <funcparams>$2</funcparams></paramdef>\n";
+	    } else {
+		print "   <paramdef>".$type;
+		print " <parameter>$parameter</parameter></paramdef>\n";
+	    }
 	}
     } else {
 	print "  <void>\n";
@@ -515,26 +537,35 @@
     my ($parameter, $section);
     my $count;
 
-    print ".TH \"$args{'module'}\" \"$args{'function'}\" \"25 May 1998\" \"API Manual\" LINUX\n";
+    print ".TH \"$args{'module'}\" 4 \"$args{'function'}\" \"25 May 1998\" \"API Manual\" LINUX\n";
 
-    print ".SH Function\n";
+    print ".SH NAME\n";
+    print $args{'function'}." \\- ".$args{'purpose'}."\n";
 
-    print ".I \"".$args{'functiontype'}."\"\n";
-    print ".B \"".$args{'function'}."\"\n";
-    print "(\n";
+    print ".SH SYNOPSIS\n";
+    print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n";
     $count = 0;
+    $parenth = "(";
+    $post = ",";
     foreach $parameter (@{$args{'parameterlist'}}) {
-	print ".I \"".$args{'parametertypes'}{$parameter}."\"\n.B \"".$parameter."\"\n";
-	if ($count != $#{$args{'parameterlist'}}) {
-	    $count++;
-	    print ",\n";
+	if ($count == $#{$args{'parameterlist'}}) {
+	    $post = ");";
 	}
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print ".BI \"".$parenth.$1."\" ".$parameter." \") (".$2.")".$post."\"\n";
+	} else {
+	    $type =~ s/([^\*])$/\1 /;
+	    print ".BI \"".$parenth.$type."\" ".$parameter." \"".$post."\"\n";
+	}
+	$count++;
+	$parenth = "";
     }
-    print ")\n";
 
     print ".SH Arguments\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
-	print ".IP \"".$args{'parametertypes'}{$parameter}." ".$parameter."\" 12\n";
+	print ".IP \"".$parameter."\" 12\n";
 	output_highlight($args{'parameters'}{$parameter});
     }
     foreach $section (@{$args{'sectionlist'}}) {
@@ -548,7 +579,7 @@
     my ($parameter, $section);
     my $count;
 
-    print ".TH \"$args{'module'}\" \"$args{'module'}\" \"25 May 1998\" \"API Manual\" LINUX\n";
+    print ".TH \"$args{'module'}\" 4 \"$args{'module'}\" \"25 May 1998\" \"API Manual\" LINUX\n";
 
     foreach $section (@{$args{'sectionlist'}}) {
 	print ".SH \"$section\"\n";
@@ -562,17 +593,35 @@
     my %args = %{$_[0]};
     my ($parameter, $section);
 
-    print "Function = ".$args{'function'}."\n";
-    print "  return type: ".$args{'functiontype'}."\n\n";
+    print "Function:\n\n";
+    $start=$args{'functiontype'}." ".$args{'function'}." (";
+    print $start;
+    $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
-	print " ".$args{'parametertypes'}{$parameter}." ".$parameter."\n";
-	print "    -> ".$args{'parameters'}{$parameter}."\n";
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print $1.$parameter.") (".$2;
+	} else {
+	    print $type." ".$parameter;
+	}
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",\n";
+	    print " " x length($start);
+	} else {
+	    print ");\n\n";
+	}
+    }
+
+    print "Arguments:\n\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print $parameter."\n\t".$args{'parameters'}{$parameter}."\n";
     }
     foreach $section (@{$args{'sectionlist'}}) {
-	print " $section:\n";
-	print "    -> ";
+	print "$section:\n\n";
 	output_highlight($args{'sections'}{$section});
     }
+    print "\n\n";
 }
 
 sub output_intro_text {
@@ -614,32 +663,46 @@
     $prototype =~ s/^inline+ //;
     $prototype =~ s/^__inline__+ //;
 
-    if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
-	$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
-	$prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
-	$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
-	$prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/)  {
+    if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {
 	$return_type = $1;
 	$function_name = $2;
 	$args = $3;
 
+	# allow for up to fours args to function pointers
+	$args =~ s/(\([^\),]+),/\1#/;
+	$args =~ s/(\([^\),]+),/\1#/;
+	$args =~ s/(\([^\),]+),/\1#/;
 #	print STDERR "ARGS = '$args'\n";
 
 	foreach $arg (split ',', $args) {
 	    # strip leading/trailing spaces
 	    $arg =~ s/^\s*//;
 	    $arg =~ s/\s*$//;
-#	    print STDERR "SCAN ARG: '$arg'\n";
-	    @args = split('\s', $arg);
 
-#	    print STDERR " -> @args\n";
-	    $param = pop @args;
-#	    print STDERR " -> @args\n";
-	    if ($param =~ m/^(\*+)(.*)/) {
-		$param = $2;
-		push @args, $1;
+	    if ($arg =~ m/\(/) {
+		# pointer-to-function
+		$arg =~ tr/#/,/;
+		$arg =~ m/[^\(]+\(\*([^\)]+)\)/;
+		$param = $1;
+		$type = $arg;
+		$type =~ s/([^\(]+\(\*)$param/\1/;
+	    } else {
+#		print STDERR "SCAN ARG: '$arg'\n";
+		@args = split('\s', $arg);
+
+#		print STDERR " -> @args\n";
+		$param = pop @args;
+#		print STDERR " -> @args\n";
+		if ($param =~ m/^(\*+)(.*)/) {
+		    $param = $2;
+		    push @args, $1;
+		}
+		$type = join " ", @args;
 	    }
-	    $type = join " ", @args;
 
 	    if ($type eq "" && $param eq "...")
 	    {
diff -u --recursive --new-file v2.3.99-pre5/linux/scripts/usb/procusb linux/scripts/usb/procusb
--- v2.3.99-pre5/linux/scripts/usb/procusb	Thu Nov 11 20:11:56 1999
+++ linux/scripts/usb/procusb	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-#!/usr/bin/perl
-
-# Reads /proc/bus/usb/devices and selectively lists and/or
-# interprets it.
-
-$DEVFILENAME = "/proc/bus/usb/devices";
-$PROGNAME = $0;
-
-print "\n";
-
-$TAGS = $ARGV[0];		# save user TAGS
-if (length ($TAGS) == 0)
-{
-	print "usage: $PROGNAME tags\n";
-	print "  where 'tags' can be any number of 'TBDPCIE' or 'A(LL)'\n";
-	exit 1;
-}
-
-$ALL = ($TAGS =~ /all/i) || ($TAGS =~ /a/i);
-
-# TBD: Check that $TAGS is valid.
-if (! $ALL)
-{
-}
-
-if (! open (DEVNUM, "<$DEVFILENAME"))
-{
-	print "$PROGNAME: cannot open '$DEVFILENAME'\n";
-	exit 1;
-}
-
-while ($line = <DEVNUM>)	# read a text line from DEVNUM
-{
-	if (($ALL) || ($line =~ /^[$TAGS]:/i))	# any of TAGS at beg. of line?
-	{
-		print "$line";	# still has newline char on it
-				# TBD: add more/paging functionality.
-	}
-} # end while DEVNUM
-
-close (DEVNUM);
-print "\n";
-
-# END.
diff -u --recursive --new-file v2.3.99-pre5/linux/scripts/usb/usbtree linux/scripts/usb/usbtree
--- v2.3.99-pre5/linux/scripts/usb/usbtree	Thu Nov 11 20:11:56 1999
+++ linux/scripts/usb/usbtree	Wed Dec 31 16:00:00 1969
@@ -1,90 +0,0 @@
-#!/usr/bin/perl
-
-# Reads /proc/bus/usb/devices and selectively lists and/or
-# interprets it.
-
-$DEVFILENAME = "/proc/bus/usb/devices";
-$PROGNAME = $0;
-
-print "\n";
-
-$TAGS = $ARGV[0];		# save user TAGS
-if (length ($TAGS) == 0)
-{
-}
-
-if (! open (DEVNUM, "<$DEVFILENAME"))
-{
-	print "$PROGNAME: cannot open '$DEVFILENAME'\n";
-	exit 1;
-}
-
-while ($line = <DEVNUM>)	# read a text line from DEVNUM
-{
-	# skip all lines except those that begin with "T:" or "D:" or "I:".
-	if (($line !~ "^T:") && ($line !~ "^I:") && ($line !~ "^D:"))
-	{
-		next;	# to the next line
-	}
-
-	chomp $line;		# remove line endings
-
-	# First convert '=' signs to spaces.
-	$line =~ tr/=/ /;
-
-	# and convert all ( and ) to spaces.
-	$line =~ tr/(/ /;
-	$line =~ tr/)/ /;
-
-	# split the line at spaces.
-	@fields = split / +/, $line;
-
-	if ($line =~ "^T:")
-	{
-		# split yields: $level, $port, $devnum, $speed, $maxchild.
-
-		$level  = @fields [2];
-		$port   = @fields [6];
-		$devnum = @fields [10];
-		$speed  = @fields [12];
-		$maxchild = @fields [14];
-		$devclass = "?";
-		$intclass = "?";
-		$driver   = "?";
-
-		if (($devnum == -1) && ($level == 0))
-		{
-			print "/:  Dev# -1, root hub/$maxchild ports, $speed Mbps\n";
-		}
-		next;
-	} # end T: line
-	elsif ($line =~ "^D:")
-	{ # for D: line
-		$devclass = @fields [5];
-		next;
-	}
-	else
-	{ # for I: line
-		$intclass = @fields [9];
-		$ifnum    = @fields [2];
-		$driver   = @fields [15];
-	} # end I: line
-
-	if ($level > 1)
-	{
-		$temp = $level;
-		while ($temp > 1)
-		{
-			print "    ";
-			$temp--;
-		}
-	}
-	
-	print sprintf ("|__ Port# $port: Dev# $devnum, If# $ifnum, Class=$devclass, Ifc=$intclass, Driver=$driver%s, $speed Mbps\n",
-		($maxchild == 0) ? "" : ("/" . $maxchild . " ports"));
-} # end while DEVNUM
-
-close (DEVNUM);
-print "\n";
-
-# END.
